diff options
17 files changed, 1643 insertions, 45 deletions
| @@ -6,6 +6,7 @@ CHANGELOG RoundCube Webmail  - Use current mailbox name in template (#1485256)  - Better fix for skipping untagged responses (#1485261)  - Added pspell support patch by Kris Steinhoff (#1483960) +- Enable spellchecker for HTML editor (#1485114)  2008/08/09 (alec)  ---------- diff --git a/bin/html2text.php b/bin/html2text.php index 0f0e6ae14..2650bf2d6 100644 --- a/bin/html2text.php +++ b/bin/html2text.php @@ -6,6 +6,6 @@ require INSTALL_PATH.'program/include/iniset.php';  $converter = new html2text($HTTP_RAW_POST_DATA);  header('Content-Type: text/plain; charset=UTF-8'); -print html_entity_decode($converter->get_text(), ENT_COMPAT, 'UTF-8'); +print html_entity_decode(trim($converter->get_text()), ENT_COMPAT, 'UTF-8');  ?> diff --git a/program/js/app.js b/program/js/app.js index 998efd7a2..c82ebf948 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -195,6 +195,8 @@ function rcube_webmail()              {              this.env.spellcheck.spelling_state_observer = function(s){ ref.set_spellcheck_state(s); };              this.set_spellcheck_state('ready'); +            if (rcube_find_object('_is_html').value == '1') +              this.display_spellcheck_controls(false);              }            if (this.env.drafts_mailbox)              this.enable_command('savedraft', true); @@ -204,9 +206,9 @@ function rcube_webmail()            this.enable_command('select-all', 'select-none', 'expunge', true);          if (this.env.messagecount  -	    && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox  -		|| this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter))  -		|| this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter)))) +            && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox  +              || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter))  +              || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter))))            this.enable_command('purge', true);          this.set_page_buttons(); @@ -855,11 +857,13 @@ function rcube_webmail()          break;        case 'spellcheck': -        if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) -          { +        if (window.tinyMCE && tinyMCE.get('compose-body')) { +          tinyMCE.execCommand('mceSpellCheck', true); +        } +        else if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) {            this.env.spellcheck.spellCheck(this.env.spellcheck.check_link);            this.set_spellcheck_state('checking'); -          } +        }          break;        case 'savedraft': @@ -1899,16 +1903,12 @@ function rcube_webmail()        }      // check for empty body -    if ((!window.tinyMCE || !tinyMCE.get('compose-body')) -	&& input_message.value == '' -	&& !confirm(this.get_label('nobodywarning'))) +    if ((!window.tinyMCE || !tinyMCE.get('compose-body')) && input_message.value == '' && !confirm(this.get_label('nobodywarning')))        {        input_message.focus();        return false;        } -    else if (window.tinyMCE && tinyMCE.get('compose-body') -	&& !tinyMCE.get('compose-body').getContent() -	&& !confirm(this.get_label('nobodywarning'))) +    else if (window.tinyMCE && tinyMCE.get('compose-body') && !tinyMCE.get('compose-body').getContent() && !confirm(this.get_label('nobodywarning')))        {        tinyMCE.get('compose-body').focus();        return false; @@ -1917,6 +1917,13 @@ function rcube_webmail()      return true;      }; +  this.display_spellcheck_controls = function(vis) +  { +    if (this.env.spellcheck) { +      this.env.spellcheck.check_link.style.visibility = vis ? 'visible' : 'hidden'; +      this.env.spellcheck.switch_lan_pic.style.visibility = vis ? 'visible' : 'hidden'; +    } +  };    this.set_spellcheck_state = function(s)      { diff --git a/program/js/editor.js b/program/js/editor.js index 6fdbadccd..38c9b7168 100644 --- a/program/js/editor.js +++ b/program/js/editor.js @@ -15,26 +15,28 @@  // Initialize the message editor -function rcmail_editor_init(skin_path, editor_lang) -  { -  tinyMCE.init({ mode : "textareas", -                 editor_selector : "mce_editor", -                 accessibility_focus : false, -                 apply_source_formatting : true, -                 theme : "advanced", -                 language : editor_lang, -                 plugins : "emotions,media,nonbreaking,table,searchreplace,visualchars,directionality", -                 theme_advanced_buttons1 : "bold,italic,underline,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,outdent,indent,separator,link,unlink,emotions,charmap,code,forecolor,backcolor,fontselect,fontsizeselect, separator,undo,redo,image,media,ltr,rtl", -                 theme_advanced_buttons2 : "", -                 theme_advanced_buttons3 : "", -                 theme_advanced_toolbar_location : "top", -                 theme_advanced_toolbar_align : "left", -                 extended_valid_elements : "font[face|size|color|style],span[id|class|align|style]", -                 content_css : skin_path + "/editor_content.css", -                 external_image_list_url : "program/js/editor_images.js", -		 rc_client: rcube_webmail_client -               }); -  } +function rcmail_editor_init(skin_path, editor_lang, spellcheck) +{ +  tinyMCE.init({  +    mode : "textareas", +    editor_selector : "mce_editor", +    accessibility_focus : false, +    apply_source_formatting : true, +    theme : "advanced", +    language : editor_lang, +    plugins : "emotions,media,nonbreaking,table,searchreplace,visualchars,directionality" + (spellcheck ? ",spellchecker" : ""), +    theme_advanced_buttons1 : "bold,italic,underline,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,outdent,indent,separator,link,unlink,emotions,charmap,code,forecolor,backcolor,fontselect,fontsizeselect, separator" + (spellcheck ? ",spellchecker" : "") + ",undo,redo,image,media,ltr,rtl", +    theme_advanced_buttons2 : "", +    theme_advanced_buttons3 : "", +    theme_advanced_toolbar_location : "top", +    theme_advanced_toolbar_align : "left", +    extended_valid_elements : "font[face|size|color|style],span[id|class|align|style]", +    content_css : skin_path + "/editor_content.css", +    external_image_list_url : "program/js/editor_images.js", +    spellchecker_languages : (rcmail.env.spellcheck_langs ? rcmail.env.spellcheck_langs : "Dansk=da,Deutsch=de,+English=en,Espanol=es,Francais=fr,Italiano=it,Nederlands=nl,Polski=pl,Portugues=pt,Suomi=fi,Svenska=sv"), +    rc_client: rcube_webmail_client +  }); +}  // Toggle between the HTML and Plain Text editors @@ -63,6 +65,7 @@ function rcmail_toggle_editor(toggler)      composeElement.value = htmlText;      tinyMCE.execCommand('mceAddControl', true, 'compose-body');      htmlFlag.value = "1"; +    rcmail.display_spellcheck_controls(false);      }    else      { @@ -72,6 +75,7 @@ function rcmail_toggle_editor(toggler)      rcmail_html2plain(existingHtml);      tinyMCE.execCommand('mceRemoveControl', true, 'compose-body');      htmlFlag.value = "0"; +    rcmail.display_spellcheck_controls(true);      }    } @@ -82,7 +86,7 @@ function rcmail_html2plain(htmlText)    http_request.onerror = function(o) { rcmail_handle_toggle_error(o); };    http_request.oncomplete = function(o) { rcmail_set_text_value(o); };    var url = rcmail.env.bin_path+'html2text.php'; -  console.log('HTTP request: ' + url); +  //console.log('HTTP request: ' + url);    http_request.POST(url, htmlText, 'application/octet-stream');    } diff --git a/program/js/tiny_mce/plugins/spellchecker/classes/EnchantSpell.php b/program/js/tiny_mce/plugins/spellchecker/classes/EnchantSpell.php new file mode 100755 index 000000000..fb6e67c43 --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/classes/EnchantSpell.php @@ -0,0 +1,66 @@ +<?php
 +/**
 + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
 + *
 + * This class was contributed by Michel Weimerskirch.
 + *
 + * @author Moxiecode
 + * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
 + */
 +
 +class EnchantSpell extends SpellChecker {
 +	/**
 +	 * Spellchecks an array of words.
 +	 *
 +	 * @param String $lang Selected language code (like en_US or de_DE). Shortcodes like "en" and "de" work with enchant >= 1.4.1
 +	 * @param Array $words Array of words to check.
 +	 * @return Array of misspelled words.
 +	 */
 +	function &checkWords($lang, $words) {
 +		$r = enchant_broker_init();
 +		
 +		if (enchant_broker_dict_exists($r,$lang)) {
 +			$d = enchant_broker_request_dict($r, $lang);
 +			
 +			$returnData = array();
 +			foreach($words as $key => $value) {
 +				$correct = enchant_dict_check($d, $value);
 +				if(!$correct) {
 +					$returnData[] = trim($value);
 +				}
 +			}
 +	
 +			return $returnData;
 +			enchant_broker_free_dict($d);
 +		} else {
 +
 +		}
 +		enchant_broker_free($r);
 +	}
 +
 +	/**
 +	 * Returns suggestions for a specific word.
 +	 *
 +	 * @param String $lang Selected language code (like en_US or de_DE). Shortcodes like "en" and "de" work with enchant >= 1.4.1
 +	 * @param String $word Specific word to get suggestions for.
 +	 * @return Array of suggestions for the specified word.
 +	 */
 +	function &getSuggestions($lang, $word) {
 +		$r = enchant_broker_init();
 +		$suggs = array();
 +
 +		if (enchant_broker_dict_exists($r,$lang)) {
 +			$d = enchant_broker_request_dict($r, $lang);
 +			$suggs = enchant_dict_suggest($d, $word);
 +
 +			enchant_broker_free_dict($d);
 +		} else {
 +
 +		}
 +		enchant_broker_free($r);
 +
 +		return $suggs;
 +	}
 +}
 +
 +?>
 diff --git a/program/js/tiny_mce/plugins/spellchecker/classes/GoogleSpell.php b/program/js/tiny_mce/plugins/spellchecker/classes/GoogleSpell.php new file mode 100755 index 000000000..53d4300e3 --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/classes/GoogleSpell.php @@ -0,0 +1,158 @@ +<?php
 +/**
 + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
 + *
 + * @author Moxiecode
 + * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
 + */
 +
 +class GoogleSpell extends SpellChecker {
 +	/**
 +	 * Spellchecks an array of words.
 +	 *
 +	 * @param {String} $lang Language code like sv or en.
 +	 * @param {Array} $words Array of words to spellcheck.
 +	 * @return {Array} Array of misspelled words.
 +	 */
 +	function &checkWords($lang, $words) {
 +		$wordstr = implode(' ', $words);
 +		$matches = $this->_getMatches($lang, $wordstr);
 +		$words = array();
 +
 +		for ($i=0; $i<count($matches); $i++)
 +			$words[] = $this->_unhtmlentities(mb_substr($wordstr, $matches[$i][1], $matches[$i][2], "UTF-8"));
 +
 +		return $words;
 +	}
 +
 +	/**
 +	 * Returns suggestions of for a specific word.
 +	 *
 +	 * @param {String} $lang Language code like sv or en.
 +	 * @param {String} $word Specific word to get suggestions for.
 +	 * @return {Array} Array of suggestions for the specified word.
 +	 */
 +	function &getSuggestions($lang, $word) {
 +		$sug = array();
 +		$osug = array();
 +		$matches = $this->_getMatches($lang, $word);
 +
 +		if (count($matches) > 0)
 +			$sug = explode("\t", utf8_encode($this->_unhtmlentities($matches[0][4])));
 +
 +		// Remove empty
 +		foreach ($sug as $item) {
 +			if ($item)
 +				$osug[] = $item;
 +		}
 +
 +		return $osug;
 +	}
 +
 +	function &_getMatches($lang, $str) {
 +		$server = "www.google.com";
 +		$port = 443;
 +		$path = "/tbproxy/spell?lang=" . $lang . "&hl=en";
 +		$host = "www.google.com";
 +		$url = "https://" . $server;
 +
 +		// Setup XML request
 +		$xml = '<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>' . $str . '</text></spellrequest>';
 +
 +		$header  = "POST ".$path." HTTP/1.0 \r\n";
 +		$header .= "MIME-Version: 1.0 \r\n";
 +		$header .= "Content-type: application/PTI26 \r\n";
 +		$header .= "Content-length: ".strlen($xml)." \r\n";
 +		$header .= "Content-transfer-encoding: text \r\n";
 +		$header .= "Request-number: 1 \r\n";
 +		$header .= "Document-type: Request \r\n";
 +		$header .= "Interface-Version: Test 1.4 \r\n";
 +		$header .= "Connection: close \r\n\r\n";
 +		$header .= $xml;
 +
 +		// Use curl if it exists
 +		if (function_exists('curl_init')) {
 +			// Use curl
 +			$ch = curl_init();
 +			curl_setopt($ch, CURLOPT_URL,$url);
 +			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 +			curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $header);
 +			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
 +			$xml = curl_exec($ch);
 +			curl_close($ch);
 +		} else {
 +			// Use raw sockets
 +			$fp = fsockopen("ssl://" . $server, $port, $errno, $errstr, 30);
 +			if ($fp) {
 +				// Send request
 +				fwrite($fp, $header);
 +
 +				// Read response
 +				$xml = "";
 +				while (!feof($fp))
 +					$xml .= fgets($fp, 128);
 +
 +				fclose($fp);
 +			} else
 +				echo "Could not open SSL connection to google.";
 +		}
 +
 +		// Grab and parse content
 +		$matches = array();
 +		preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $xml, $matches, PREG_SET_ORDER);
 +
 +		return $matches;
 +	}
 +
 +	function _unhtmlentities($string) {
 +		$string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);
 +		$string = preg_replace('~&#([0-9]+);~e', 'chr(\\1)', $string);
 +
 +		$trans_tbl = get_html_translation_table(HTML_ENTITIES);
 +		$trans_tbl = array_flip($trans_tbl);
 +
 +		return strtr($string, $trans_tbl);
 +	}
 +}
 +
 +// Patch in multibyte support
 +if (!function_exists('mb_substr')) {
 +	function mb_substr($str, $start, $len = '', $encoding="UTF-8"){
 +		$limit = strlen($str);
 +
 +		for ($s = 0; $start > 0;--$start) {// found the real start
 +			if ($s >= $limit)
 +				break;
 +
 +			if ($str[$s] <= "\x7F")
 +				++$s;
 +			else {
 +				++$s; // skip length
 +
 +				while ($str[$s] >= "\x80" && $str[$s] <= "\xBF")
 +					++$s;
 +			}
 +		}
 +
 +		if ($len == '')
 +			return substr($str, $s);
 +		else
 +			for ($e = $s; $len > 0; --$len) {//found the real end
 +				if ($e >= $limit)
 +					break;
 +
 +				if ($str[$e] <= "\x7F")
 +					++$e;
 +				else {
 +					++$e;//skip length
 +
 +					while ($str[$e] >= "\x80" && $str[$e] <= "\xBF" && $e < $limit)
 +						++$e;
 +				}
 +			}
 +
 +		return substr($str, $s, $e - $s);
 +	}
 +}
 +
 +?>
 diff --git a/program/js/tiny_mce/plugins/spellchecker/classes/PSpell.php b/program/js/tiny_mce/plugins/spellchecker/classes/PSpell.php new file mode 100755 index 000000000..45448d070 --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/classes/PSpell.php @@ -0,0 +1,81 @@ +<?php
 +/**
 + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
 + *
 + * @author Moxiecode
 + * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
 + */
 +
 +class PSpell extends SpellChecker {
 +	/**
 +	 * Spellchecks an array of words.
 +	 *
 +	 * @param {String} $lang Language code like sv or en.
 +	 * @param {Array} $words Array of words to spellcheck.
 +	 * @return {Array} Array of misspelled words.
 +	 */
 +	function &checkWords($lang, $words) {
 +		$plink = $this->_getPLink($lang);
 +
 +		$outWords = array();
 +		foreach ($words as $word) {
 +			if (!pspell_check($plink, trim($word)))
 +				$outWords[] = utf8_encode($word);
 +		}
 +
 +		return $outWords;
 +	}
 +
 +	/**
 +	 * Returns suggestions of for a specific word.
 +	 *
 +	 * @param {String} $lang Language code like sv or en.
 +	 * @param {String} $word Specific word to get suggestions for.
 +	 * @return {Array} Array of suggestions for the specified word.
 +	 */
 +	function &getSuggestions($lang, $word) {
 +		$words = pspell_suggest($this->_getPLink($lang), $word);
 +
 +		for ($i=0; $i<count($words); $i++)
 +			$words[$i] = utf8_encode($words[$i]);
 +
 +		return $words;
 +	}
 +
 +	/**
 +	 * Opens a link for pspell.
 +	 */
 +	function &_getPLink($lang) {
 +		// Check for native PSpell support
 +		if (!function_exists("pspell_new"))
 +			$this->throwError("PSpell support not found in PHP installation.");
 +
 +		// Setup PSpell link
 +		$plink = pspell_new(
 +			$lang,
 +			$this->_config['PSpell.spelling'],
 +			$this->_config['PSpell.jargon'],
 +			$this->_config['PSpell.encoding'],
 +			$this->_config['PSpell.mode']
 +		);
 +
 +		// Setup PSpell link
 +/*		if (!$plink) {
 +			$pspellConfig = pspell_config_create(
 +				$lang,
 +				$this->_config['PSpell.spelling'],
 +				$this->_config['PSpell.jargon'],
 +				$this->_config['PSpell.encoding']
 +			);
 +
 +			$plink = pspell_new_config($pspell_config);
 +		}*/
 +
 +		if (!$plink)
 +			$this->throwError("No PSpell link found opened.");
 +
 +		return $plink;
 +	}
 +}
 +
 +?>
 diff --git a/program/js/tiny_mce/plugins/spellchecker/classes/PSpellShell.php b/program/js/tiny_mce/plugins/spellchecker/classes/PSpellShell.php new file mode 100755 index 000000000..0bc57de7e --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/classes/PSpellShell.php @@ -0,0 +1,112 @@ +<?php
 +/**
 + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
 + *
 + * @author Moxiecode
 + * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
 + */
 +
 +class PSpellShell extends SpellChecker {
 +	/**
 +	 * Spellchecks an array of words.
 +	 *
 +	 * @param {String} $lang Language code like sv or en.
 +	 * @param {Array} $words Array of words to spellcheck.
 +	 * @return {Array} Array of misspelled words.
 +	 */
 +	function &checkWords($lang, $words) {
 +		$cmd = $this->_getCMD($lang);
 +
 +		if ($fh = fopen($this->_tmpfile, "w")) {
 +			fwrite($fh, "!\n");
 +
 +			foreach($words as $key => $value)
 +				fwrite($fh, "^" . $value . "\n");
 +
 +			fclose($fh);
 +		} else
 +			$this->throwError("PSpell support was not found.");
 +
 +		$data = shell_exec($cmd);
 +		@unlink($this->_tmpfile);
 +
 +		$returnData = array();
 +		$dataArr = preg_split("/[\r\n]/", $data, -1, PREG_SPLIT_NO_EMPTY);
 +
 +		foreach ($dataArr as $dstr) {
 +			$matches = array();
 +
 +			// Skip this line.
 +			if (strpos($dstr, "@") === 0)
 +				continue;
 +
 +			preg_match("/\& ([^ ]+) .*/i", $dstr, $matches);
 +
 +			if (!empty($matches[1]))
 +				$returnData[] = utf8_encode(trim($matches[1]));
 +		}
 +
 +		return $returnData;
 +	}
 +
 +	/**
 +	 * Returns suggestions of for a specific word.
 +	 *
 +	 * @param {String} $lang Language code like sv or en.
 +	 * @param {String} $word Specific word to get suggestions for.
 +	 * @return {Array} Array of suggestions for the specified word.
 +	 */
 +	function &getSuggestions($lang, $word) {
 +		$cmd = $this->_getCMD($lang);
 +
 +        if (function_exists("mb_convert_encoding"))
 +            $word = mb_convert_encoding($word, "ISO-8859-1", mb_detect_encoding($word, "UTF-8"));
 +        else
 +            $word = utf8_encode($word);
 +
 +		if ($fh = fopen($this->_tmpfile, "w")) {
 +			fwrite($fh, "!\n");
 +			fwrite($fh, "^$word\n");
 +			fclose($fh);
 +		} else
 +			$this->throwError("Error opening tmp file.");
 +
 +		$data = shell_exec($cmd);
 +		@unlink($this->_tmpfile);
 +
 +		$returnData = array();
 +		$dataArr = preg_split("/\n/", $data, -1, PREG_SPLIT_NO_EMPTY);
 +
 +		foreach($dataArr as $dstr) {
 +			$matches = array();
 +
 +			// Skip this line.
 +			if (strpos($dstr, "@") === 0)
 +				continue;
 +
 +			preg_match("/\&[^:]+:(.*)/i", $dstr, $matches);
 +
 +			if (!empty($matches[1])) {
 +				$words = array_slice(explode(',', $matches[1]), 0, 10);
 +
 +				for ($i=0; $i<count($words); $i++)
 +					$words[$i] = trim($words[$i]);
 +
 +				return $words;
 +			}
 +		}
 +
 +		return array();
 +	}
 +
 +	function _getCMD($lang) {
 +		$this->_tmpfile = tempnam($this->_config['PSpellShell.tmp'], "tinyspell");
 +
 +		if(preg_match("#win#i", php_uname()))
 +			return $this->_config['PSpellShell.aspell'] . " -a --lang=". escapeshellarg($lang) . " --encoding=utf-8 -H < " . $this->_tmpfile . " 2>&1";
 +
 +		return "cat ". $this->_tmpfile ." | " . $this->_config['PSpellShell.aspell'] . " -a --encoding=utf-8 -H --lang=". escapeshellarg($lang);
 +	}
 +}
 +
 +?>
 diff --git a/program/js/tiny_mce/plugins/spellchecker/classes/SpellChecker.php b/program/js/tiny_mce/plugins/spellchecker/classes/SpellChecker.php new file mode 100755 index 000000000..d6800391a --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/classes/SpellChecker.php @@ -0,0 +1,61 @@ +<?php
 +/**
 + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
 + *
 + * @author Moxiecode
 + * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
 + */
 +
 +class SpellChecker {
 +	/**
 +	 * Constructor.
 +	 *
 +	 * @param $config Configuration name/value array.
 +	 */
 +	function SpellChecker(&$config) {
 +		$this->_config = $config;
 +	}
 +
 +	/**
 +	 * Simple loopback function everything that gets in will be send back.
 +	 *
 +	 * @param $args.. Arguments.
 +	 * @return {Array} Array of all input arguments. 
 +	 */
 +	function &loopback(/* args.. */) {
 +		return func_get_args();
 +	}
 +
 +	/**
 +	 * Spellchecks an array of words.
 +	 *
 +	 * @param {String} $lang Language code like sv or en.
 +	 * @param {Array} $words Array of words to spellcheck.
 +	 * @return {Array} Array of misspelled words.
 +	 */
 +	function &checkWords($lang, $words) {
 +		return $words;
 +	}
 +
 +	/**
 +	 * Returns suggestions of for a specific word.
 +	 *
 +	 * @param {String} $lang Language code like sv or en.
 +	 * @param {String} $word Specific word to get suggestions for.
 +	 * @return {Array} Array of suggestions for the specified word.
 +	 */
 +	function &getSuggestions($lang, $word) {
 +		return array();
 +	}
 +
 +	/**
 +	 * Throws an error message back to the user. This will stop all execution.
 +	 *
 +	 * @param {String} $str Message to send back to user.
 +	 */
 +	function throwError($str) {
 +		die('{"result":null,"id":null,"error":{"errstr":"' . addslashes($str) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}');
 +	}
 +}
 +
 +?>
 diff --git a/program/js/tiny_mce/plugins/spellchecker/classes/utils/JSON.php b/program/js/tiny_mce/plugins/spellchecker/classes/utils/JSON.php new file mode 100755 index 000000000..1c4611676 --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/classes/utils/JSON.php @@ -0,0 +1,595 @@ +<?php +/** + * $Id: JSON.php 40 2007-06-18 11:43:15Z spocke $ + * + * @package MCManager.utils + * @author Moxiecode + * @copyright Copyright © 2007, Moxiecode Systems AB, All rights reserved. + */ + +define('JSON_BOOL', 1); +define('JSON_INT', 2); +define('JSON_STR', 3); +define('JSON_FLOAT', 4); +define('JSON_NULL', 5); +define('JSON_START_OBJ', 6); +define('JSON_END_OBJ', 7); +define('JSON_START_ARRAY', 8); +define('JSON_END_ARRAY', 9); +define('JSON_KEY', 10); +define('JSON_SKIP', 11); + +define('JSON_IN_ARRAY', 30); +define('JSON_IN_OBJECT', 40); +define('JSON_IN_BETWEEN', 50); + +class Moxiecode_JSONReader { +	var $_data, $_len, $_pos; +	var $_value, $_token; +	var $_location, $_lastLocations; +	var $_needProp; + +	function Moxiecode_JSONReader($data) { +		$this->_data = $data; +		$this->_len = strlen($data); +		$this->_pos = -1; +		$this->_location = JSON_IN_BETWEEN; +		$this->_lastLocations = array(); +		$this->_needProp = false; +	} + +	function getToken() { +		return $this->_token; +	} + +	function getLocation() { +		return $this->_location; +	} + +	function getTokenName() { +		switch ($this->_token) { +			case JSON_BOOL: +				return 'JSON_BOOL'; + +			case JSON_INT: +				return 'JSON_INT'; + +			case JSON_STR: +				return 'JSON_STR'; + +			case JSON_FLOAT: +				return 'JSON_FLOAT'; + +			case JSON_NULL: +				return 'JSON_NULL'; + +			case JSON_START_OBJ: +				return 'JSON_START_OBJ'; + +			case JSON_END_OBJ: +				return 'JSON_END_OBJ'; + +			case JSON_START_ARRAY: +				return 'JSON_START_ARRAY'; + +			case JSON_END_ARRAY: +				return 'JSON_END_ARRAY'; + +			case JSON_KEY: +				return 'JSON_KEY'; +		} + +		return 'UNKNOWN'; +	} + +	function getValue() { +		return $this->_value; +	} + +	function readToken() { +		$chr = $this->read(); + +		if ($chr != null) { +			switch ($chr) { +				case '[': +					$this->_lastLocation[] = $this->_location; +					$this->_location = JSON_IN_ARRAY; +					$this->_token = JSON_START_ARRAY; +					$this->_value = null; +					$this->readAway(); +					return true; + +				case ']': +					$this->_location = array_pop($this->_lastLocation); +					$this->_token = JSON_END_ARRAY; +					$this->_value = null; +					$this->readAway(); + +					if ($this->_location == JSON_IN_OBJECT) +						$this->_needProp = true; + +					return true; + +				case '{': +					$this->_lastLocation[] = $this->_location; +					$this->_location = JSON_IN_OBJECT; +					$this->_needProp = true; +					$this->_token = JSON_START_OBJ; +					$this->_value = null; +					$this->readAway(); +					return true; + +				case '}': +					$this->_location = array_pop($this->_lastLocation); +					$this->_token = JSON_END_OBJ; +					$this->_value = null; +					$this->readAway(); + +					if ($this->_location == JSON_IN_OBJECT) +						$this->_needProp = true; + +					return true; + +				// String +				case '"': +				case '\'': +					return $this->_readString($chr); + +				// Null +				case 'n': +					return $this->_readNull(); + +				// Bool +				case 't': +				case 'f': +					return $this->_readBool($chr); + +				default: +					// Is number +					if (is_numeric($chr) || $chr == '-' || $chr == '.') +						return $this->_readNumber($chr); + +					return true; +			} +		} + +		return false; +	} + +	function _readBool($chr) { +		$this->_token = JSON_BOOL; +		$this->_value = $chr == 't'; + +		if ($chr == 't') +			$this->skip(3); // rue +		else +			$this->skip(4); // alse + +		$this->readAway(); + +		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp) +			$this->_needProp = true; + +		return true; +	} + +	function _readNull() { +		$this->_token = JSON_NULL; +		$this->_value = null; + +		$this->skip(3); // ull +		$this->readAway(); + +		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp) +			$this->_needProp = true; + +		return true; +	} + +	function _readString($quote) { +		$output = ""; +		$this->_token = JSON_STR; +		$endString = false; + +		while (($chr = $this->peek()) != -1) { +			switch ($chr) { +				case '\\': +					// Read away slash +					$this->read(); + +					// Read escape code +					$chr = $this->read(); +					switch ($chr) { +							case 't': +								$output .= "\t"; +								break; + +							case 'b': +								$output .= "\b"; +								break; + +							case 'f': +								$output .= "\f"; +								break; + +							case 'r': +								$output .= "\r"; +								break; + +							case 'n': +								$output .= "\n"; +								break; + +							case 'u': +								$output .= $this->_int2utf8(hexdec($this->read(4))); +								break; + +							default: +								$output .= $chr; +								break; +					} + +					break; + +					case '\'': +					case '"': +						if ($chr == $quote) +							$endString = true; + +						$chr = $this->read(); +						if ($chr != -1 && $chr != $quote) +							$output .= $chr; + +						break; + +					default: +						$output .= $this->read(); +			} + +			// String terminated +			if ($endString) +				break; +		} + +		$this->readAway(); +		$this->_value = $output; + +		// Needed a property +		if ($this->_needProp) { +			$this->_token = JSON_KEY; +			$this->_needProp = false; +			return true; +		} + +		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp) +			$this->_needProp = true; + +		return true; +	} + +	function _int2utf8($int) { +		$int = intval($int); + +		switch ($int) { +			case 0: +				return chr(0); + +			case ($int & 0x7F): +				return chr($int); + +			case ($int & 0x7FF): +				return chr(0xC0 | (($int >> 6) & 0x1F)) . chr(0x80 | ($int & 0x3F)); + +			case ($int & 0xFFFF): +				return chr(0xE0 | (($int >> 12) & 0x0F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr (0x80 | ($int & 0x3F)); + +			case ($int & 0x1FFFFF): +				return chr(0xF0 | ($int >> 18)) . chr(0x80 | (($int >> 12) & 0x3F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr(0x80 | ($int & 0x3F)); +		} +	} + +	function _readNumber($start) { +		$value = ""; +		$isFloat = false; + +		$this->_token = JSON_INT; +		$value .= $start; + +		while (($chr = $this->peek()) != -1) { +			if (is_numeric($chr) || $chr == '-' || $chr == '.') { +				if ($chr == '.') +					$isFloat = true; + +				$value .= $this->read(); +			} else +				break; +		} + +		$this->readAway(); + +		if ($isFloat) { +			$this->_token = JSON_FLOAT; +			$this->_value = floatval($value); +		} else +			$this->_value = intval($value); + +		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp) +			$this->_needProp = true; + +		return true; +	} + +	function readAway() { +		while (($chr = $this->peek()) != null) { +			if ($chr != ':' && $chr != ',' && $chr != ' ') +				return; + +			$this->read(); +		} +	} + +	function read($len = 1) { +		if ($this->_pos < $this->_len) { +			if ($len > 1) { +				$str = substr($this->_data, $this->_pos + 1, $len); +				$this->_pos += $len; + +				return $str; +			} else +				return $this->_data[++$this->_pos]; +		} + +		return null; +	} + +	function skip($len) { +		$this->_pos += $len; +	} + +	function peek() { +		if ($this->_pos < $this->_len) +			return $this->_data[$this->_pos + 1]; + +		return null; +	} +} + +/** + * This class handles JSON stuff. + * + * @package MCManager.utils + */ +class Moxiecode_JSON { +	function Moxiecode_JSON() { +	} + +	function decode($input) { +		$reader = new Moxiecode_JSONReader($input); + +		return $this->readValue($reader); +	} + +	function readValue(&$reader) { +		$this->data = array(); +		$this->parents = array(); +		$this->cur =& $this->data; +		$key = null; +		$loc = JSON_IN_ARRAY; + +		while ($reader->readToken()) { +			switch ($reader->getToken()) { +				case JSON_STR: +				case JSON_INT: +				case JSON_BOOL: +				case JSON_FLOAT: +				case JSON_NULL: +					switch ($reader->getLocation()) { +						case JSON_IN_OBJECT: +							$this->cur[$key] = $reader->getValue(); +							break; + +						case JSON_IN_ARRAY: +							$this->cur[] = $reader->getValue(); +							break; + +						default: +							return $reader->getValue(); +					} +					break; + +				case JSON_KEY: +					$key = $reader->getValue(); +					break; + +				case JSON_START_OBJ: +				case JSON_START_ARRAY: +					if ($loc == JSON_IN_OBJECT) +						$this->addArray($key); +					else +						$this->addArray(null); + +					$cur =& $obj; + +					$loc = $reader->getLocation(); +					break; + +				case JSON_END_OBJ: +				case JSON_END_ARRAY: +					$loc = $reader->getLocation(); + +					if (count($this->parents) > 0) { +						$this->cur =& $this->parents[count($this->parents) - 1]; +						array_pop($this->parents); +					} +					break; +			} +		} + +		return $this->data[0]; +	} + +	// This method was needed since PHP is crapy and doesn't have pointers/references +	function addArray($key) { +		$this->parents[] =& $this->cur; +		$ar = array(); + +		if ($key) +			$this->cur[$key] =& $ar; +		else +			$this->cur[] =& $ar; + +		$this->cur =& $ar; +	} + +	function getDelim($index, &$reader) { +		switch ($reader->getLocation()) { +			case JSON_IN_ARRAY: +			case JSON_IN_OBJECT: +				if ($index > 0) +					return ","; +				break; +		} + +		return ""; +	} + +	function encode($input) { +		switch (gettype($input)) { +			case 'boolean': +				return $input ? 'true' : 'false'; + +			case 'integer': +				return (int) $input; + +			case 'float': +			case 'double': +				return (float) $input; + +			case 'NULL': +				return 'null'; + +			case 'string': +				return $this->encodeString($input); + +			case 'array': +				return $this->_encodeArray($input); + +			case 'object': +				return $this->_encodeArray(get_object_vars($input)); +		} + +		return ''; +	} + +	function encodeString($input) { +		// Needs to be escaped +		if (preg_match('/[^a-zA-Z0-9]/', $input)) { +			$output = ''; + +			for ($i=0; $i<strlen($input); $i++) { +				switch ($input[$i]) { +					case "\b": +						$output .= "\\b"; +						break; + +					case "\t": +						$output .= "\\t"; +						break; + +					case "\f": +						$output .= "\\f"; +						break; + +					case "\r": +						$output .= "\\r"; +						break; + +					case "\n": +						$output .= "\\n"; +						break; + +					case '\\': +						$output .= "\\\\"; +						break; + +					case '\'': +						$output .= "\\'"; +						break; + +					case '"': +						$output .= '\"'; +						break; + +					default: +						$byte = ord($input[$i]); + +						if (($byte & 0xE0) == 0xC0) { +							$char = pack('C*', $byte, ord($input[$i + 1])); +							$i += 1; +							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char))); +						} if (($byte & 0xF0) == 0xE0) { +							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2])); +							$i += 2; +							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char))); +						} if (($byte & 0xF8) == 0xF0) { +							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2], ord($input[$i + 3]))); +							$i += 3; +							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char))); +						} if (($byte & 0xFC) == 0xF8) { +							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2], ord($input[$i + 3]), ord($input[$i + 4]))); +							$i += 4; +							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char))); +						} if (($byte & 0xFE) == 0xFC) { +							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2], ord($input[$i + 3]), ord($input[$i + 4]), ord($input[$i + 5]))); +							$i += 5; +							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char))); +						} else if ($byte < 128) +							$output .= $input[$i]; +				} +			} + +			return '"' . $output . '"'; +		} + +		return '"' . $input . '"'; +	} + +	function _utf82utf16($utf8) { +		if (function_exists('mb_convert_encoding')) +			return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + +		switch (strlen($utf8)) { +			case 1: +				return $utf8; + +			case 2: +				return chr(0x07 & (ord($utf8[0]) >> 2)) . chr((0xC0 & (ord($utf8[0]) << 6)) | (0x3F & ord($utf8[1]))); + +			case 3: +				return chr((0xF0 & (ord($utf8[0]) << 4)) | (0x0F & (ord($utf8[1]) >> 2))) . chr((0xC0 & (ord($utf8[1]) << 6)) | (0x7F & ord($utf8[2]))); +		} + +		return ''; +	} + +	function _encodeArray($input) { +		$output = ''; +		$isIndexed = true; + +		$keys = array_keys($input); +		for ($i=0; $i<count($keys); $i++) { +			if (!is_int($keys[$i])) { +				$output .= $this->encodeString($keys[$i]) . ':' . $this->encode($input[$keys[$i]]); +				$isIndexed = false; +			} else +				$output .= $this->encode($input[$keys[$i]]); + +			if ($i != count($keys) - 1) +				$output .= ','; +		} + +		return $isIndexed ? '[' . $output . ']' : '{' . $output . '}'; +	} +} + +?> diff --git a/program/js/tiny_mce/plugins/spellchecker/classes/utils/Logger.php b/program/js/tiny_mce/plugins/spellchecker/classes/utils/Logger.php new file mode 100755 index 000000000..bc501ea75 --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/classes/utils/Logger.php @@ -0,0 +1,268 @@ +<?php
 +/**
 + * $Id: Logger.class.php 10 2007-05-27 10:55:12Z spocke $
 + *
 + * @package MCFileManager.filesystems
 + * @author Moxiecode
 + * @copyright Copyright © 2005, Moxiecode Systems AB, All rights reserved.
 + */
 +
 +// File type contstants
 +define('MC_LOGGER_DEBUG', 0);
 +define('MC_LOGGER_INFO', 10);
 +define('MC_LOGGER_WARN', 20);
 +define('MC_LOGGER_ERROR', 30);
 +define('MC_LOGGER_FATAL', 40);
 +
 +/**
 + * Logging utility class. This class handles basic logging with levels, log rotation and custom log formats. It's
 + * designed to be compact but still powerful and flexible.
 + */
 +class Moxiecode_Logger {
 +	// Private fields
 +	var $_path;
 +	var $_filename;
 +	var $_maxSize;
 +	var $_maxFiles;
 +	var $_maxSizeBytes;
 +	var $_level;
 +	var $_format;
 +
 +	/**
 +	 * Constructs a new logger instance.
 +	 */
 +	function Moxiecode_Logger() {
 +		$this->_path = "";
 +		$this->_filename = "{level}.log";
 +		$this->setMaxSize("100k");
 +		$this->_maxFiles = 10;
 +		$this->_level = MC_LOGGER_DEBUG;
 +		$this->_format = "[{time}] [{level}] {message}";
 +	}
 +
 +	/**
 +	 * Sets the current log level, use the MC_LOGGER constants.
 +	 *
 +	 * @param int $level Log level instance for example MC_LOGGER_DEBUG.
 +	 */
 +	function setLevel($level) {
 +		if (is_string($level)) {
 +			switch (strtolower($level)) {
 +				case "debug":
 +					$level = MC_LOGGER_DEBUG;
 +					break;
 +
 +				case "info":
 +					$level = MC_LOGGER_INFO;
 +					break;
 +
 +				case "warn":
 +				case "warning":
 +					$level = MC_LOGGER_WARN;
 +					break;
 +
 +				case "error":
 +					$level = MC_LOGGER_ERROR;
 +					break;
 +
 +				case "fatal":
 +					$level = MC_LOGGER_FATAL;
 +					break;
 +
 +				default:
 +					$level = MC_LOGGER_FATAL;
 +			}
 +		}
 +
 +		$this->_level = $level;
 +	}
 +
 +	/**
 +	 * Returns the current log level for example MC_LOGGER_DEBUG.
 +	 *
 +	 * @return int Current log level for example MC_LOGGER_DEBUG.
 +	 */
 +	function getLevel() {
 +		return $this->_level;
 +	}
 +
 +	function setPath($path) {
 +		$this->_path = $path;
 +	}
 +
 +	function getPath() {
 +		return $this->_path;
 +	}
 +
 +	function setFileName($file_name) {
 +		$this->_filename = $file_name;
 +	}
 +
 +	function getFileName() {
 +		return $this->_filename;
 +	}
 +
 +	function setFormat($format) {
 +		$this->_format = $format;
 +	}
 +
 +	function getFormat() {
 +		return $this->_format;
 +	}
 +
 +	function setMaxSize($size) {
 +		// Fix log max size
 +		$logMaxSizeBytes = intval(preg_replace("/[^0-9]/", "", $size));
 +
 +		// Is KB
 +		if (strpos((strtolower($size)), "k") > 0)
 +			$logMaxSizeBytes *= 1024;
 +
 +		// Is MB
 +		if (strpos((strtolower($size)), "m") > 0)
 +			$logMaxSizeBytes *= (1024 * 1024);
 +
 +		$this->_maxSizeBytes = $logMaxSizeBytes;
 +		$this->_maxSize = $size;
 +	}
 +
 +	function getMaxSize() {
 +		return $this->_maxSize;
 +	}
 +
 +	function setMaxFiles($max_files) {
 +		$this->_maxFiles = $max_files;
 +	}
 +
 +	function getMaxFiles() {
 +		return $this->_maxFiles;
 +	}
 +
 +	function debug($msg) {
 +		$args = func_get_args();
 +		$this->_logMsg(MC_LOGGER_DEBUG, implode(', ', $args));
 +	}
 +
 +	function info($msg) {
 +		$args = func_get_args();
 +		$this->_logMsg(MC_LOGGER_INFO, implode(', ', $args));
 +	}
 +
 +	function warn($msg) {
 +		$args = func_get_args();
 +		$this->_logMsg(MC_LOGGER_WARN, implode(', ', $args));
 +	}
 +
 +	function error($msg) {
 +		$args = func_get_args();
 +		$this->_logMsg(MC_LOGGER_ERROR, implode(', ', $args));
 +	}
 +
 +	function fatal($msg) {
 +		$args = func_get_args();
 +		$this->_logMsg(MC_LOGGER_FATAL, implode(', ', $args));
 +	}
 +
 +	function isDebugEnabled() {
 +		return $this->_level >= MC_LOGGER_DEBUG;
 +	}
 +
 +	function isInfoEnabled() {
 +		return $this->_level >= MC_LOGGER_INFO;
 +	}
 +
 +	function isWarnEnabled() {
 +		return $this->_level >= MC_LOGGER_WARN;
 +	}
 +
 +	function isErrorEnabled() {
 +		return $this->_level >= MC_LOGGER_ERROR;
 +	}
 +
 +	function isFatalEnabled() {
 +		return $this->_level >= MC_LOGGER_FATAL;
 +	}
 +
 +	function _logMsg($level, $message) {
 +		$roll = false;
 +
 +		if ($level < $this->_level)
 +			return;
 +
 +		$logFile = $this->toOSPath($this->_path . "/" . $this->_filename);
 +
 +		switch ($level) {
 +			case MC_LOGGER_DEBUG:
 +				$levelName = "DEBUG";
 +				break;
 +
 +			case MC_LOGGER_INFO:
 +				$levelName = "INFO";
 +				break;
 +
 +			case MC_LOGGER_WARN:
 +				$levelName = "WARN";
 +				break;
 +
 +			case MC_LOGGER_ERROR:
 +				$levelName = "ERROR";
 +				break;
 +
 +			case MC_LOGGER_FATAL:
 +				$levelName = "FATAL";
 +				break;
 +		}
 +
 +		$logFile = str_replace('{level}', strtolower($levelName), $logFile);
 +
 +		$text = $this->_format;
 +		$text = str_replace('{time}', date("Y-m-d H:i:s"), $text);
 +		$text = str_replace('{level}', strtolower($levelName), $text);
 +		$text = str_replace('{message}', $message, $text);
 +		$message = $text . "\r\n";
 +
 +		// Check filesize
 +		if (file_exists($logFile)) {
 +			$size = @filesize($logFile);
 +
 +			if ($size + strlen($message) > $this->_maxSizeBytes)
 +				$roll = true;
 +		}
 +
 +		// Roll if the size is right
 +		if ($roll) {
 +			for ($i=$this->_maxFiles-1; $i>=1; $i--) {
 +				$rfile = $this->toOSPath($logFile . "." . $i);
 +				$nfile = $this->toOSPath($logFile . "." . ($i+1));
 +
 +				if (@file_exists($rfile))
 +					@rename($rfile, $nfile);
 +			}
 +
 +			@rename($logFile, $this->toOSPath($logFile . ".1"));
 +
 +			// Delete last logfile
 +			$delfile = $this->toOSPath($logFile . "." . ($this->_maxFiles + 1));
 +			if (@file_exists($delfile))
 +				@unlink($delfile);
 +		}
 +
 +		// Append log line
 +		if (($fp = @fopen($logFile, "a")) != null) {
 +			@fputs($fp, $message);
 +			@fflush($fp);
 +			@fclose($fp);
 +		}
 +	}
 +
 +	/**
 +	 * Converts a Unix path to OS specific path.
 +	 *
 +	 * @param String $path Unix path to convert.
 +	 */
 +	function toOSPath($path) {
 +		return str_replace("/", DIRECTORY_SEPARATOR, $path);
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/program/js/tiny_mce/plugins/spellchecker/config.php b/program/js/tiny_mce/plugins/spellchecker/config.php new file mode 100755 index 000000000..827749e48 --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/config.php @@ -0,0 +1,33 @@ +<?php
 +
 +	/** start RoundCube specific code */
 +	
 +	define('INSTALL_PATH', preg_replace('/program\/js\/.+$/', '', getcwd()));
 +	require_once INSTALL_PATH . 'program/include/iniset.php';
 +	
 +	$rcmail_config = new rcube_config();
 +	$config['general.engine'] = $rcmail_config->get('spellcheck_engine') == 'pspell' ? 'PSpell' : 'GoogleSpell';
 +	
 +	/** end RoundCube specific code */
 +
 +	// General settings
 +	//$config['general.engine'] = 'GoogleSpell';
 +	//$config['general.engine'] = 'PSpell';
 +	//$config['general.engine'] = 'PSpellShell';
 +	//$config['general.remote_rpc_url'] = 'http://some.other.site/some/url/rpc.php';
 +
 +	// PSpell settings
 +	$config['PSpell.mode'] = PSPELL_FAST;
 +	$config['PSpell.spelling'] = "";
 +	$config['PSpell.jargon'] = "";
 +	$config['PSpell.encoding'] = "";
 +
 +	// PSpellShell settings
 +	$config['PSpellShell.mode'] = PSPELL_FAST;
 +	$config['PSpellShell.aspell'] = '/usr/bin/aspell';
 +	$config['PSpellShell.tmp'] = '/tmp';
 +	
 +	// Windows PSpellShell settings
 +	//$config['PSpellShell.aspell'] = '"c:\Program Files\Aspell\bin\aspell.exe"';
 +	//$config['PSpellShell.tmp'] = 'c:/temp';
 +?>
 diff --git a/program/js/tiny_mce/plugins/spellchecker/editor_plugin.js b/program/js/tiny_mce/plugins/spellchecker/editor_plugin.js index 9cb679961..915fc400d 100644 --- a/program/js/tiny_mce/plugins/spellchecker/editor_plugin.js +++ b/program/js/tiny_mce/plugins/spellchecker/editor_plugin.js @@ -1 +1 @@ -(function(){var JSONRequest=tinymce.util.JSONRequest,each=tinymce.each,DOM=tinymce.DOM;tinymce.create('tinymce.plugins.SpellcheckerPlugin',{getInfo:function(){return{longname:'Spellchecker',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker',version:tinymce.majorVersion+"."+tinymce.minorVersion};},init:function(ed,url){var t=this,cm;t.url=url;t.editor=ed;ed.addCommand('mceSpellCheck',function(){if(!t.active){ed.setProgressState(1);t._sendRPC('checkWords',[t.selectedLang,t._getWords()],function(r){if(r.length>0){t.active=1;t._markWords(r);ed.setProgressState(0);ed.nodeChanged();}else{ed.setProgressState(0);ed.windowManager.alert('spellchecker.no_mpell');}});}else t._done();});ed.onInit.add(function(){if(ed.settings.content_css!==false)ed.dom.loadCSS(url+'/css/content.css');});ed.onClick.add(t._showMenu,t);ed.onContextMenu.add(t._showMenu,t);ed.onBeforeGetContent.add(function(){if(t.active)t._removeWords();});ed.onNodeChange.add(function(ed,cm){cm.setActive('spellchecker',t.active);});ed.onSetContent.add(function(){t._done();});ed.onBeforeGetContent.add(function(){t._done();});ed.onBeforeExecCommand.add(function(ed,cmd){if(cmd=='mceFullScreen')t._done();});t.languages={};each(ed.getParam('spellchecker_languages','+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv','hash'),function(v,k){if(k.indexOf('+')===0){k=k.substring(1);t.selectedLang=v;}t.languages[k]=v;});},createControl:function(n,cm){var t=this,c,ed=t.editor;if(n=='spellchecker'){c=cm.createSplitButton(n,{title:'spellchecker.desc',cmd:'mceSpellCheck',scope:t});c.onRenderMenu.add(function(c,m){m.add({title:'spellchecker.langs','class':'mceMenuItemTitle'}).setDisabled(1);each(t.languages,function(v,k){var o={icon:1},mi;o.onclick=function(){mi.setSelected(1);t.selectedItem.setSelected(0);t.selectedItem=mi;t.selectedLang=v;};o.title=k;mi=m.add(o);mi.setSelected(v==t.selectedLang);if(v==t.selectedLang)t.selectedItem=mi;})});return c;}},_walk:function(n,f){var d=this.editor.getDoc(),w;if(d.createTreeWalker){w=d.createTreeWalker(n,NodeFilter.SHOW_TEXT,null,false);while((n=w.nextNode())!=null)f.call(this,n);}else tinymce.walk(n,f,'childNodes');},_getSeparators:function(){var re='',i,str=this.editor.getParam('spellchecker_word_separator_chars','\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}����������������\u201d\u201c');for(i=0;i<str.length;i++)re+='\\'+str.charAt(i);return re;},_getWords:function(){var ed=this.editor,wl=[],tx='',lo={};this._walk(ed.getBody(),function(n){if(n.nodeType==3)tx+=n.nodeValue+' ';});tx=tx.replace(new RegExp('([0-9]|['+this._getSeparators()+'])','g'),' ');tx=tinymce.trim(tx.replace(/(\s+)/g,' '));each(tx.split(' '),function(v){if(!lo[v]){wl.push(v);lo[v]=1;}});return wl;},_removeWords:function(w){var ed=this.editor,dom=ed.dom,se=ed.selection,b=se.getBookmark();each(dom.select('span').reverse(),function(n){if(n&&(dom.hasClass(n,'mceItemHiddenSpellWord')||dom.hasClass(n,'mceItemHidden'))){if(!w||dom.decode(n.innerHTML)==w)dom.remove(n,1);}});se.moveToBookmark(b);},_markWords:function(wl){var r1,r2,r3,r4,r5,w='',ed=this.editor,re=this._getSeparators(),dom=ed.dom,nl=[];var se=ed.selection,b=se.getBookmark();each(wl,function(v){w+=(w?'|':'')+v;});r1=new RegExp('(['+re+'])('+w+')(['+re+'])','g');r2=new RegExp('^('+w+')','g');r3=new RegExp('('+w+')(['+re+']?)$','g');r4=new RegExp('^('+w+')(['+re+']?)$','g');r5=new RegExp('('+w+')(['+re+'])','g');this._walk(this.editor.getBody(),function(n){if(n.nodeType==3){nl.push(n);}});each(nl,function(n){var v;if(n.nodeType==3){v=n.nodeValue;if(r1.test(v)||r2.test(v)||r3.test(v)||r4.test(v)){v=dom.encode(v);v=v.replace(r5,'<span class="mceItemHiddenSpellWord">$1</span>$2');v=v.replace(r3,'<span class="mceItemHiddenSpellWord">$1</span>$2');dom.replace(dom.create('span',{'class':'mceItemHidden'},v),n);}}});se.moveToBookmark(b);},_showMenu:function(ed,e){var t=this,ed=t.editor,m=t._menu,p1,dom=ed.dom,vp=dom.getViewPort(ed.getWin());if(!m){p1=DOM.getPos(ed.getContentAreaContainer());m=ed.controlManager.createDropMenu('spellcheckermenu',{offset_x:p1.x,offset_y:p1.y,'class':'mceNoIcons'});t._menu=m;}if(dom.hasClass(e.target,'mceItemHiddenSpellWord')){m.removeAll();m.add({title:'spellchecker.wait','class':'mceMenuItemTitle'}).setDisabled(1);t._sendRPC('getSuggestions',[t.selectedLang,dom.decode(e.target.innerHTML)],function(r){m.removeAll();if(r.length>0){m.add({title:'spellchecker.sug','class':'mceMenuItemTitle'}).setDisabled(1);each(r,function(v){m.add({title:v,onclick:function(){dom.replace(ed.getDoc().createTextNode(v),e.target);t._checkDone();}});});m.addSeparator();}else m.add({title:'spellchecker.no_sug','class':'mceMenuItemTitle'}).setDisabled(1);m.add({title:'spellchecker.ignore_word',onclick:function(){dom.remove(e.target,1);t._checkDone();}});m.add({title:'spellchecker.ignore_words',onclick:function(){t._removeWords(dom.decode(e.target.innerHTML));t._checkDone();}});m.update();});ed.selection.select(e.target);p1=dom.getPos(e.target);m.showMenu(p1.x,p1.y+e.target.offsetHeight-vp.y);return tinymce.dom.Event.cancel(e);}else m.hideMenu();},_checkDone:function(){var t=this,ed=t.editor,dom=ed.dom,o;each(dom.select('span'),function(n){if(n&&dom.hasClass(n,'mceItemHiddenSpellWord')){o=true;return false;}});if(!o)t._done();},_done:function(){var t=this,la=t.active;if(t.active){t.active=0;t._removeWords();if(t._menu)t._menu.hideMenu();if(la)t.editor.nodeChanged();}},_sendRPC:function(m,p,cb){var t=this,url=t.editor.getParam("spellchecker_rpc_url","{backend}");if(url=='{backend}'){t.editor.setProgressState(0);alert('Please specify: spellchecker_rpc_url');return;}JSONRequest.sendRPC({url:url,method:m,params:p,success:cb,error:function(e,x){t.editor.setProgressState(0);t.editor.windowManager.alert(e.errstr||('Error response: '+x.responseText));}});}});tinymce.PluginManager.add('spellchecker',tinymce.plugins.SpellcheckerPlugin);})();
\ No newline at end of file +(function(){var JSONRequest=tinymce.util.JSONRequest,each=tinymce.each,DOM=tinymce.DOM;tinymce.create('tinymce.plugins.SpellcheckerPlugin',{getInfo:function(){return{longname:'Spellchecker',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker',version:"2.0.2"};},init:function(ed,url){var t=this,cm;t.url=url;t.editor=ed;ed.addCommand('mceSpellCheck',function(){if(!t.active){ed.setProgressState(1);t._sendRPC('checkWords',[t.selectedLang,t._getWords()],function(r){if(r.length>0){t.active=1;t._markWords(r);ed.setProgressState(0);ed.nodeChanged();}else{ed.setProgressState(0);ed.windowManager.alert('spellchecker.no_mpell');}});}else t._done();});ed.onInit.add(function(){if(ed.settings.content_css!==false)ed.dom.loadCSS(url+'/css/content.css');});ed.onClick.add(t._showMenu,t);ed.onContextMenu.add(t._showMenu,t);ed.onBeforeGetContent.add(function(){if(t.active)t._removeWords();});ed.onNodeChange.add(function(ed,cm){cm.setActive('spellchecker',t.active);});ed.onSetContent.add(function(){t._done();});ed.onBeforeGetContent.add(function(){t._done();});ed.onBeforeExecCommand.add(function(ed,cmd){if(cmd=='mceFullScreen')t._done();});t.languages={};each(ed.getParam('spellchecker_languages','+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv','hash'),function(v,k){if(k.indexOf('+')===0){k=k.substring(1);t.selectedLang=v;}t.languages[k]=v;});},createControl:function(n,cm){var t=this,c,ed=t.editor;if(n=='spellchecker'){c=cm.createSplitButton(n,{title:'spellchecker.desc',cmd:'mceSpellCheck',scope:t});c.onRenderMenu.add(function(c,m){m.add({title:'spellchecker.langs','class':'mceMenuItemTitle'}).setDisabled(1);each(t.languages,function(v,k){var o={icon:1},mi;o.onclick=function(){mi.setSelected(1);t.selectedItem.setSelected(0);t.selectedItem=mi;t.selectedLang=v;};o.title=k;mi=m.add(o);mi.setSelected(v==t.selectedLang);if(v==t.selectedLang)t.selectedItem=mi;})});return c;}},_walk:function(n,f){var d=this.editor.getDoc(),w;if(d.createTreeWalker){w=d.createTreeWalker(n,NodeFilter.SHOW_TEXT,null,false);while((n=w.nextNode())!=null)f.call(this,n);}else tinymce.walk(n,f,'childNodes');},_getSeparators:function(){var re='',i,str=this.editor.getParam('spellchecker_word_separator_chars','\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}����������������\u201d\u201c');for(i=0;i<str.length;i++)re+='\\'+str.charAt(i);return re;},_getWords:function(){var ed=this.editor,wl=[],tx='',lo={};this._walk(ed.getBody(),function(n){if(n.nodeType==3)tx+=n.nodeValue+' ';});tx=tx.replace(new RegExp('([0-9]|['+this._getSeparators()+'])','g'),' ');tx=tinymce.trim(tx.replace(/(\s+)/g,' '));each(tx.split(' '),function(v){if(!lo[v]){wl.push(v);lo[v]=1;}});return wl;},_removeWords:function(w){var ed=this.editor,dom=ed.dom,se=ed.selection,b=se.getBookmark();each(dom.select('span').reverse(),function(n){if(n&&(dom.hasClass(n,'mceItemHiddenSpellWord')||dom.hasClass(n,'mceItemHidden'))){if(!w||dom.decode(n.innerHTML)==w)dom.remove(n,1);}});se.moveToBookmark(b);},_markWords:function(wl){var r1,r2,r3,r4,r5,w='',ed=this.editor,re=this._getSeparators(),dom=ed.dom,nl=[];var se=ed.selection,b=se.getBookmark();each(wl,function(v){w+=(w?'|':'')+v;});r1=new RegExp('(['+re+'])('+w+')(['+re+'])','g');r2=new RegExp('^('+w+')','g');r3=new RegExp('('+w+')(['+re+']?)$','g');r4=new RegExp('^('+w+')(['+re+']?)$','g');r5=new RegExp('('+w+')(['+re+'])','g');this._walk(this.editor.getBody(),function(n){if(n.nodeType==3){nl.push(n);}});each(nl,function(n){var v;if(n.nodeType==3){v=n.nodeValue;if(r1.test(v)||r2.test(v)||r3.test(v)||r4.test(v)){v=dom.encode(v);v=v.replace(r5,'<span class="mceItemHiddenSpellWord">$1</span>$2');v=v.replace(r3,'<span class="mceItemHiddenSpellWord">$1</span>$2');dom.replace(dom.create('span',{'class':'mceItemHidden'},v),n);}}});se.moveToBookmark(b);},_showMenu:function(ed,e){var t=this,ed=t.editor,m=t._menu,p1,dom=ed.dom,vp=dom.getViewPort(ed.getWin());if(!m){p1=DOM.getPos(ed.getContentAreaContainer());m=ed.controlManager.createDropMenu('spellcheckermenu',{offset_x:p1.x,offset_y:p1.y,'class':'mceNoIcons'});t._menu=m;}if(dom.hasClass(e.target,'mceItemHiddenSpellWord')){m.removeAll();m.add({title:'spellchecker.wait','class':'mceMenuItemTitle'}).setDisabled(1);t._sendRPC('getSuggestions',[t.selectedLang,dom.decode(e.target.innerHTML)],function(r){m.removeAll();if(r.length>0){m.add({title:'spellchecker.sug','class':'mceMenuItemTitle'}).setDisabled(1);each(r,function(v){m.add({title:v,onclick:function(){dom.replace(ed.getDoc().createTextNode(v),e.target);t._checkDone();}});});m.addSeparator();}else m.add({title:'spellchecker.no_sug','class':'mceMenuItemTitle'}).setDisabled(1);m.add({title:'spellchecker.ignore_word',onclick:function(){dom.remove(e.target,1);t._checkDone();}});m.add({title:'spellchecker.ignore_words',onclick:function(){t._removeWords(dom.decode(e.target.innerHTML));t._checkDone();}});m.update();});ed.selection.select(e.target);p1=dom.getPos(e.target);m.showMenu(p1.x,p1.y+e.target.offsetHeight-vp.y);return tinymce.dom.Event.cancel(e);}else m.hideMenu();},_checkDone:function(){var t=this,ed=t.editor,dom=ed.dom,o;each(dom.select('span'),function(n){if(n&&dom.hasClass(n,'mceItemHiddenSpellWord')){o=true;return false;}});if(!o)t._done();},_done:function(){var t=this,la=t.active;if(t.active){t.active=0;t._removeWords();if(t._menu)t._menu.hideMenu();if(la)t.editor.nodeChanged();}},_sendRPC:function(m,p,cb){var t=this,url=t.editor.getParam("spellchecker_rpc_url",this.url+'/rpc.php');if(url=='{backend}'){t.editor.setProgressState(0);alert('Please specify: spellchecker_rpc_url');return;}JSONRequest.sendRPC({url:url,method:m,params:p,success:cb,error:function(e,x){t.editor.setProgressState(0);t.editor.windowManager.alert(e.errstr||('Error response: '+x.responseText));}});}});tinymce.PluginManager.add('spellchecker',tinymce.plugins.SpellcheckerPlugin);})();
\ No newline at end of file diff --git a/program/js/tiny_mce/plugins/spellchecker/editor_plugin_src.js b/program/js/tiny_mce/plugins/spellchecker/editor_plugin_src.js index c913c4603..84a9989f6 100644 --- a/program/js/tiny_mce/plugins/spellchecker/editor_plugin_src.js +++ b/program/js/tiny_mce/plugins/spellchecker/editor_plugin_src.js @@ -15,7 +15,7 @@  				author : 'Moxiecode Systems AB',
  				authorurl : 'http://tinymce.moxiecode.com',
  				infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker',
 -				version : tinymce.majorVersion + "." + tinymce.minorVersion
 +				version : "2.0.2"
  			};
  		},
 @@ -312,7 +312,7 @@  		},
  		_sendRPC : function(m, p, cb) {
 -			var t = this, url = t.editor.getParam("spellchecker_rpc_url", "{backend}");
 +			var t = this, url = t.editor.getParam("spellchecker_rpc_url", this.url+'/rpc.php');
  			if (url == '{backend}') {
  				t.editor.setProgressState(0);
 diff --git a/program/js/tiny_mce/plugins/spellchecker/includes/general.php b/program/js/tiny_mce/plugins/spellchecker/includes/general.php new file mode 100755 index 000000000..9a1214569 --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/includes/general.php @@ -0,0 +1,98 @@ +<?php +/** + * general.php + * + * @package MCManager.includes + * @author Moxiecode + * @copyright Copyright © 2007, Moxiecode Systems AB, All rights reserved. + */ + +@error_reporting(E_ALL ^ E_NOTICE); +$config = array(); + +require_once(dirname(__FILE__) . "/../classes/utils/Logger.php"); +require_once(dirname(__FILE__) . "/../classes/utils/JSON.php"); +require_once(dirname(__FILE__) . "/../config.php"); +require_once(dirname(__FILE__) . "/../classes/SpellChecker.php"); + +if (isset($config['general.engine'])) +	require_once(dirname(__FILE__) . "/../classes/" . $config["general.engine"] . ".php"); + +/** + * Returns an request value by name without magic quoting. + * + * @param String $name Name of parameter to get. + * @param String $default_value Default value to return if value not found. + * @return String request value by name without magic quoting or default value. + */ +function getRequestParam($name, $default_value = false, $sanitize = false) { +	if (!isset($_REQUEST[$name])) +		return $default_value; + +	if (is_array($_REQUEST[$name])) { +		$newarray = array(); + +		foreach ($_REQUEST[$name] as $name => $value) +			$newarray[formatParam($name, $sanitize)] = formatParam($value, $sanitize); + +		return $newarray; +	} + +	return formatParam($_REQUEST[$name], $sanitize); +} + +function &getLogger() { +	global $mcLogger, $man; + +	if (isset($man)) +		$mcLogger = $man->getLogger(); + +	if (!$mcLogger) { +		$mcLogger = new Moxiecode_Logger(); + +		// Set logger options +		$mcLogger->setPath(dirname(__FILE__) . "/../logs"); +		$mcLogger->setMaxSize("100kb"); +		$mcLogger->setMaxFiles("10"); +		$mcLogger->setFormat("{time} - {message}"); +	} + +	return $mcLogger; +} + +function debug($msg) { +	$args = func_get_args(); + +	$log = getLogger(); +	$log->debug(implode(', ', $args)); +} + +function info($msg) { +	$args = func_get_args(); + +	$log = getLogger(); +	$log->info(implode(', ', $args)); +} + +function error($msg) { +	$args = func_get_args(); + +	$log = getLogger(); +	$log->error(implode(', ', $args)); +} + +function warn($msg) { +	$args = func_get_args(); + +	$log = getLogger(); +	$log->warn(implode(', ', $args)); +} + +function fatal($msg) { +	$args = func_get_args(); + +	$log = getLogger(); +	$log->fatal(implode(', ', $args)); +} + +?>
\ No newline at end of file diff --git a/program/js/tiny_mce/plugins/spellchecker/rpc.php b/program/js/tiny_mce/plugins/spellchecker/rpc.php new file mode 100755 index 000000000..a0072ae9c --- /dev/null +++ b/program/js/tiny_mce/plugins/spellchecker/rpc.php @@ -0,0 +1,111 @@ +<?php
 +/**
 + * $Id: rpc.php 822 2008-04-28 13:45:03Z spocke $
 + *
 + * @author Moxiecode
 + * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
 + */
 +
 +require_once("./includes/general.php");
 +
 +// Set RPC response headers
 +header('Content-Type: text/plain');
 +header('Content-Encoding: UTF-8');
 +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
 +header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
 +header("Cache-Control: no-store, no-cache, must-revalidate");
 +header("Cache-Control: post-check=0, pre-check=0", false);
 +header("Pragma: no-cache");
 +
 +$raw = "";
 +
 +// Try param
 +if (isset($_POST["json_data"]))
 +	$raw = getRequestParam("json_data");
 +
 +// Try globals array
 +if (!$raw && isset($_GLOBALS) && isset($_GLOBALS["HTTP_RAW_POST_DATA"]))
 +	$raw = $_GLOBALS["HTTP_RAW_POST_DATA"];
 +
 +// Try globals variable
 +if (!$raw && isset($HTTP_RAW_POST_DATA))
 +	$raw = $HTTP_RAW_POST_DATA;
 +
 +// Try stream
 +if (!$raw) {
 +	if (!function_exists('file_get_contents')) {
 +		$fp = fopen("php://input", "r");
 +		if ($fp) {
 +			$raw = "";
 +
 +			while (!feof($fp))
 +				$raw = fread($fp, 1024);
 +
 +			fclose($fp);
 +		}
 +	} else
 +		$raw = "" . file_get_contents("php://input");
 +}
 +
 +// No input data
 +if (!$raw)
 +	die('{"result":null,"id":null,"error":{"errstr":"Could not get raw post data.","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}');
 +
 +// Passthrough request to remote server
 +if (isset($config['general.remote_rpc_url'])) {
 +	$url = parse_url($config['general.remote_rpc_url']);
 +
 +	// Setup request
 +	$req = "POST " . $url["path"] . " HTTP/1.0\r\n";
 +	$req .= "Connection: close\r\n";
 +	$req .= "Host: " . $url['host'] . "\r\n";
 +	$req .= "Content-Length: " . strlen($raw) . "\r\n";
 +	$req .= "\r\n" . $raw;
 +
 +	if (!isset($url['port']) || !$url['port'])
 +		$url['port'] = 80;
 +
 +	$errno = $errstr = "";
 +
 +	$socket = fsockopen($url['host'], intval($url['port']), $errno, $errstr, 30);
 +	if ($socket) {
 +		// Send request headers
 +		fputs($socket, $req);
 +
 +		// Read response headers and data
 +		$resp = "";
 +		while (!feof($socket))
 +				$resp .= fgets($socket, 4096);
 +
 +		fclose($socket);
 +
 +		// Split response header/data
 +		$resp = explode("\r\n\r\n", $resp);
 +		echo $resp[1]; // Output body
 +	}
 +
 +	die();
 +}
 +
 +// Get JSON data
 +$json = new Moxiecode_JSON();
 +$input = $json->decode($raw);
 +
 +// Execute RPC
 +if (isset($config['general.engine'])) {
 +	$spellchecker = new $config['general.engine']($config);
 +	$result = call_user_func_array(array($spellchecker, $input['method']), $input['params']);
 +} else
 +	die('{"result":null,"id":null,"error":{"errstr":"You must choose an spellchecker engine in the config.php file.","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}');
 +
 +// Request and response id should always be the same
 +$output = array(
 +	"id" => $input->id,
 +	"result" => $result,
 +	"error" => null
 +);
 +
 +// Return JSON encoded string
 +echo $json->encode($output);
 +
 +?>
\ No newline at end of file diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 8e5a7c2ef..06e9d0332 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -382,7 +382,7 @@ function rcmail_compose_body($attrib)    $OUTPUT->include_script('tiny_mce/tiny_mce.js');    $OUTPUT->include_script("editor.js"); -  $OUTPUT->add_script('rcmail_editor_init("$__skin_path", "'.$tinylang.'");'); +  $OUTPUT->add_script('rcmail_editor_init("$__skin_path", "'.JQ($tinylang).'", '.intval($CONFIG['enable_spellcheck']).');');    $out = $form_start ? "$form_start\n" : ''; @@ -402,11 +402,13 @@ function rcmail_compose_body($attrib)    $out .= $form_end ? "\n$form_end" : '';    // include GoogieSpell -  if (!empty($CONFIG['enable_spellcheck']) && !$isHtml) -    { -    $lang_set = ''; -    if (!empty($CONFIG['spellcheck_languages']) && is_array($CONFIG['spellcheck_languages'])) -      $lang_set = "googie.setLanguages(".array2js($CONFIG['spellcheck_languages']).");\n"; +  if (!empty($CONFIG['enable_spellcheck'])) { +    $googie_lang_set = $editor_lang_set = ''; +    if (!empty($CONFIG['spellcheck_languages']) && is_array($CONFIG['spellcheck_languages'])) { +      $googie_lang_set = "googie.setLanguages(".json_serialize($CONFIG['spellcheck_languages']).");\n"; +      foreach ($CONFIG['spellcheck_languages'] as $key => $name) +        $editor_lang_set .= ($editor_lang_set ? ',' : '') . ($key == $tinylang ? '+' : '') . JQ($name).'='.JQ($key); +    }      $OUTPUT->include_script('googiespell.js');      $OUTPUT->add_script(sprintf( @@ -425,13 +427,14 @@ function rcmail_compose_body($attrib)        JQ(Q(rcube_label('close'))),        JQ(Q(rcube_label('revertto'))),        JQ(Q(rcube_label('nospellerrors'))), -      $lang_set, +      $googie_lang_set,        substr($_SESSION['language'], 0, 2),        $attrib['id'],        JS_OBJECT_NAME), 'foot');      rcube_add_label('checking'); -    } +    $OUTPUT->set_env('spellcheck_langs', $editor_lang_set); +  }    $out .= "\n".'<iframe name="savetarget" src="program/blank.gif" style="width:0;height:0;border:none;visibility:hidden;"></iframe>'; | 
