From 5d92ed56321ad98a8bf139e138c92474c5e219d4 Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Wed, 15 Jan 2014 19:07:11 +0000 Subject: [PATCH] TinyMCE: remove the 'spellchecker' plugin. It has been disabled for a while and the back-end currently doesn't work. See #24067. Built from https://develop.svn.wordpress.org/trunk@26958 git-svn-id: http://core.svn.wordpress.org/trunk@26837 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/class-wp-editor.php | 11 +- .../plugins/spellchecker/changelog.txt | 33 - .../spellchecker/classes/EnchantSpell.php | 71 -- .../spellchecker/classes/GoogleSpell.php | 161 ----- .../plugins/spellchecker/classes/PSpell.php | 82 --- .../spellchecker/classes/PSpellShell.php | 117 --- .../spellchecker/classes/SpellChecker.php | 62 -- .../spellchecker/classes/utils/JSON.php | 595 ---------------- .../spellchecker/classes/utils/Logger.php | 268 ------- .../tinymce/plugins/spellchecker/config.php | 27 - .../plugins/spellchecker/includes/general.php | 98 --- .../js/tinymce/plugins/spellchecker/plugin.js | 672 ------------------ .../plugins/spellchecker/plugin.min.js | 1 - .../js/tinymce/plugins/spellchecker/rpc.php | 113 --- wp-includes/js/tinymce/wp-tinymce.js.gz | Bin 119219 -> 117007 bytes 15 files changed, 6 insertions(+), 2305 deletions(-) delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/changelog.txt delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/classes/EnchantSpell.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/classes/GoogleSpell.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/classes/PSpell.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/classes/SpellChecker.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/classes/utils/Logger.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/config.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/includes/general.php delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/plugin.js delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/plugin.min.js delete mode 100644 wp-includes/js/tinymce/plugins/spellchecker/rpc.php diff --git a/wp-includes/class-wp-editor.php b/wp-includes/class-wp-editor.php index 104eb11b8f..febd8be1aa 100644 --- a/wp-includes/class-wp-editor.php +++ b/wp-includes/class-wp-editor.php @@ -237,6 +237,12 @@ final class _WP_Editors { 'wpdialogs', ) ) ); + if ( ( $key = array_search( 'spellchecker', $plugins ) ) !== false ) { + // Remove 'spellchecker' from the internal plugins if added with 'tiny_mce_plugins' filter to prevent errors. + // It can be added with 'mce_external_plugins'. + unset( $plugins[$key] ); + } + if ( ! empty( $mce_external_plugins ) ) { /** * This filter loads translations for external TinyMCE 3.x plugins. @@ -326,11 +332,6 @@ final class _WP_Editors { self::$first_init['external_plugins'] = json_encode( $mce_external_plugins ); } - if ( in_array( 'spellchecker', $plugins, true ) ) { - self::$first_init['spellchecker_rpc_url'] = self::$baseurl . '/plugins/spellchecker/rpc.php'; - self::$first_init['spellchecker_language'] = self::$mce_locale; - } - // WordPress default stylesheet $mce_css = array( self::$baseurl . '/skins/wordpress/wp-content.css' ); diff --git a/wp-includes/js/tinymce/plugins/spellchecker/changelog.txt b/wp-includes/js/tinymce/plugins/spellchecker/changelog.txt deleted file mode 100644 index f41ec7fdb1..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/changelog.txt +++ /dev/null @@ -1,33 +0,0 @@ -Version 2.0.6 (2011-09-29) - Fixed incorrect position of suggestion menu. - Fixed handling of mispelled words with no suggestions in PSpellShell engine. - Fixed PSpellShell command on Windows. - Fixed bug where Javascript error is produced when enchant_dict_suggest() returns unexpected result. -Version 2.0.5 (2011-03-24) - Merged with the latest TinyMCE spellchecker version. -Version 2.0.4 (2010-12-20) - Fixed issue with the JSON class not having the correct number of parameters to ord calls. -Version 2.0.3 (2010-04-19) - Added standalone support. Will use native spellchecker for supported browsers. - Added @package phpdoc comments. Patch contributed by Jacob Santos. - Fixed some PHP missing function issue. -Version 2.0.2 (2008-04-30) - Added new EnchantSpell engine class contributed by Michel Weimerskirch. - Added new general.remote_rpc_url option, enables you to proxy requests to another server. - Fixed security hole in PSpellShell.php file if PSpellShell engine was used. -Version 2.0.1 (2008-03-07) - Fixed bug where spellchecker was auto focusing the editor in IE. -Version 2.0 (2008-01-30) - Fixed bug where the suggestions menu was placed at an incorrect location. -Version 2.0rc1 (2008-01-14) - Moved package from beta to release candidate. -Version 2.0b3 (2007-12-xx) - Fixed bug where the suggestions menu could appear at the wrong location. -Version 2.0b2 (2007-11-29) - Fixed bug where the spellchecker was removing the word when it was ignored. -Version 2.0b1 (2007-11-21) - Moved spellchecker from alpha to beta status. -Version 2.0a2 (2007-11-13) - Updated plugin so it works correctly with the TinyMCE 3.0a3 version. -Version 2.0a1 (2007-11-01) - Rewritten version for TinyMCE 3.0 this new version uses JSON RPC. diff --git a/wp-includes/js/tinymce/plugins/spellchecker/classes/EnchantSpell.php b/wp-includes/js/tinymce/plugins/spellchecker/classes/EnchantSpell.php deleted file mode 100644 index cefc8cf2ce..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/classes/EnchantSpell.php +++ /dev/null @@ -1,71 +0,0 @@ -= 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(); - - if (enchant_broker_dict_exists($r,$lang)) { - $d = enchant_broker_request_dict($r, $lang); - $suggs = enchant_dict_suggest($d, $word); - - // enchant_dict_suggest() sometimes returns NULL - if (!is_array($suggs)) - $suggs = array(); - - enchant_broker_free_dict($d); - } else { - $suggs = array(); - } - - enchant_broker_free($r); - - return $suggs; - } -} - -?> diff --git a/wp-includes/js/tinymce/plugins/spellchecker/classes/GoogleSpell.php b/wp-includes/js/tinymce/plugins/spellchecker/classes/GoogleSpell.php deleted file mode 100644 index 03e4a7848e..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/classes/GoogleSpell.php +++ /dev/null @@ -1,161 +0,0 @@ -_getMatches($lang, $wordstr); - $words = array(); - - for ($i=0; $i_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; - } - - protected function &_getMatches($lang, $str) { - $lang = preg_replace('/[^a-z\-]/i', '', $lang); - $str = preg_replace('/[\x00-\x1F\x7F]/', '', $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 = '' . $str . ''; - - $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>/', $xml, $matches, PREG_SET_ORDER); - - return $matches; - } - - protected 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/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpell.php b/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpell.php deleted file mode 100644 index 3c6424d86e..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpell.php +++ /dev/null @@ -1,82 +0,0 @@ -_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; $ithrowError("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/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php b/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php deleted file mode 100644 index 3d6d4a9a26..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php +++ /dev/null @@ -1,117 +0,0 @@ -_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 ($dstr[0] == "@") - continue; - - preg_match("/(\&|#) ([^ ]+) .*/i", $dstr, $matches); - - if (!empty($matches[2])) - $returnData[] = utf8_encode(trim($matches[2])); - } - - 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 ($dstr[0] == "@") - continue; - - preg_match("/\&[^:]+:(.*)/i", $dstr, $matches); - - if (!empty($matches[1])) { - $words = array_slice(explode(',', $matches[1]), 0, 10); - - for ($i=0; $i_tmpfile = tempnam($this->_config['PSpellShell.tmp'], "tinyspell"); - - $file = $this->_tmpfile; - $lang = preg_replace("/[^-_a-z]/", "", strtolower($lang)); - $bin = $this->_config['PSpellShell.aspell']; - - if (preg_match("#win#i", php_uname())) - return "$bin -a --lang=$lang --encoding=utf-8 -H < $file 2>&1"; - - return "cat $file | $bin -a --lang=$lang --encoding=utf-8 -H"; - } -} - -?> diff --git a/wp-includes/js/tinymce/plugins/spellchecker/classes/SpellChecker.php b/wp-includes/js/tinymce/plugins/spellchecker/classes/SpellChecker.php deleted file mode 100644 index 5d9205fe6e..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/classes/SpellChecker.php +++ /dev/null @@ -1,62 +0,0 @@ -_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/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php b/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php deleted file mode 100644 index 1f2b92caa2..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php +++ /dev/null @@ -1,595 +0,0 @@ -_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_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; $iencodeString($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/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/Logger.php b/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/Logger.php deleted file mode 100644 index a1fb4cd09e..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/Logger.php +++ /dev/null @@ -1,268 +0,0 @@ -_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/wp-includes/js/tinymce/plugins/spellchecker/config.php b/wp-includes/js/tinymce/plugins/spellchecker/config.php deleted file mode 100644 index fb92643e9f..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/config.php +++ /dev/null @@ -1,27 +0,0 @@ - diff --git a/wp-includes/js/tinymce/plugins/spellchecker/includes/general.php b/wp-includes/js/tinymce/plugins/spellchecker/includes/general.php deleted file mode 100644 index ffea3a0c1f..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/includes/general.php +++ /dev/null @@ -1,98 +0,0 @@ - $value) - $newarray[$name] = $value; - - return $newarray; - } - - return $_REQUEST[$name]; -} - -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/wp-includes/js/tinymce/plugins/spellchecker/plugin.js b/wp-includes/js/tinymce/plugins/spellchecker/plugin.js deleted file mode 100644 index 01a493a69e..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/plugin.js +++ /dev/null @@ -1,672 +0,0 @@ -/** - * Compiled inline version. (Library mode) - */ - -/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ -/*globals $code */ - -(function(exports, undefined) { - "use strict"; - - var modules = {}; - - function require(ids, callback) { - var module, defs = []; - - for (var i = 0; i < ids.length; ++i) { - module = modules[ids[i]] || resolve(ids[i]); - if (!module) { - throw 'module definition dependecy not found: ' + ids[i]; - } - - defs.push(module); - } - - callback.apply(null, defs); - } - - function define(id, dependencies, definition) { - if (typeof id !== 'string') { - throw 'invalid module definition, module id must be defined and be a string'; - } - - if (dependencies === undefined) { - throw 'invalid module definition, dependencies must be specified'; - } - - if (definition === undefined) { - throw 'invalid module definition, definition function must be specified'; - } - - require(dependencies, function() { - modules[id] = definition.apply(null, arguments); - }); - } - - function defined(id) { - return !!modules[id]; - } - - function resolve(id) { - var target = exports; - var fragments = id.split(/[.\/]/); - - for (var fi = 0; fi < fragments.length; ++fi) { - if (!target[fragments[fi]]) { - return; - } - - target = target[fragments[fi]]; - } - - return target; - } - - function expose(ids) { - for (var i = 0; i < ids.length; i++) { - var target = exports; - var id = ids[i]; - var fragments = id.split(/[.\/]/); - - for (var fi = 0; fi < fragments.length - 1; ++fi) { - if (target[fragments[fi]] === undefined) { - target[fragments[fi]] = {}; - } - - target = target[fragments[fi]]; - } - - target[fragments[fragments.length - 1]] = modules[id]; - } - } - -// Included from: js/tinymce/plugins/spellchecker/classes/DomTextMatcher.js - -/** - * DomTextMatcher.js - * - * Copyright, Moxiecode Systems AB - * Released under LGPL License. - * - * License: http://www.tinymce.com/license - * Contributing: http://www.tinymce.com/contributing - */ - -/** - * This class logic for filtering text and matching words. - * - * @class tinymce.spellcheckerplugin.TextFilter - * @private - */ -define("tinymce/spellcheckerplugin/DomTextMatcher", [], function() { - // Based on work developed by: James Padolsey http://james.padolsey.com - // released under UNLICENSE that is compatible with LGPL - // TODO: Handle contentEditable edgecase: - //

texttexttexttexttext

- return function(regex, node, schema) { - var m, matches = [], text, count = 0, doc; - var blockElementsMap, hiddenTextElementsMap, shortEndedElementsMap; - - doc = node.ownerDocument; - blockElementsMap = schema.getBlockElements(); // H1-H6, P, TD etc - hiddenTextElementsMap = schema.getWhiteSpaceElements(); // TEXTAREA, PRE, STYLE, SCRIPT - shortEndedElementsMap = schema.getShortEndedElements(); // BR, IMG, INPUT - - function getMatchIndexes(m) { - if (!m[0]) { - throw 'findAndReplaceDOMText cannot handle zero-length matches'; - } - - var index = m.index; - - return [index, index + m[0].length, [m[0]]]; - } - - function getText(node) { - var txt; - - if (node.nodeType === 3) { - return node.data; - } - - if (hiddenTextElementsMap[node.nodeName] && !blockElementsMap[node.nodeName]) { - return ''; - } - - txt = ''; - - if (blockElementsMap[node.nodeName] || shortEndedElementsMap[node.nodeName]) { - txt += '\n'; - } - - if ((node = node.firstChild)) { - do { - txt += getText(node); - } while ((node = node.nextSibling)); - } - - return txt; - } - - function stepThroughMatches(node, matches, replaceFn) { - var startNode, endNode, startNodeIndex, - endNodeIndex, innerNodes = [], atIndex = 0, curNode = node, - matchLocation = matches.shift(), matchIndex = 0; - - out: while (true) { - if (blockElementsMap[curNode.nodeName] || shortEndedElementsMap[curNode.nodeName]) { - atIndex++; - } - - if (curNode.nodeType === 3) { - if (!endNode && curNode.length + atIndex >= matchLocation[1]) { - // We've found the ending - endNode = curNode; - endNodeIndex = matchLocation[1] - atIndex; - } else if (startNode) { - // Intersecting node - innerNodes.push(curNode); - } - - if (!startNode && curNode.length + atIndex > matchLocation[0]) { - // We've found the match start - startNode = curNode; - startNodeIndex = matchLocation[0] - atIndex; - } - - atIndex += curNode.length; - } - - if (startNode && endNode) { - curNode = replaceFn({ - startNode: startNode, - startNodeIndex: startNodeIndex, - endNode: endNode, - endNodeIndex: endNodeIndex, - innerNodes: innerNodes, - match: matchLocation[2], - matchIndex: matchIndex - }); - - // replaceFn has to return the node that replaced the endNode - // and then we step back so we can continue from the end of the - // match: - atIndex -= (endNode.length - endNodeIndex); - startNode = null; - endNode = null; - innerNodes = []; - matchLocation = matches.shift(); - matchIndex++; - - if (!matchLocation) { - break; // no more matches - } - } else if ((!hiddenTextElementsMap[curNode.nodeName] || blockElementsMap[curNode.nodeName]) && curNode.firstChild) { - // Move down - curNode = curNode.firstChild; - continue; - } else if (curNode.nextSibling) { - // Move forward: - curNode = curNode.nextSibling; - continue; - } - - // Move forward or up: - while (true) { - if (curNode.nextSibling) { - curNode = curNode.nextSibling; - break; - } else if (curNode.parentNode !== node) { - curNode = curNode.parentNode; - } else { - break out; - } - } - } - } - - /** - * Generates the actual replaceFn which splits up text nodes - * and inserts the replacement element. - */ - function genReplacer(nodeName) { - var makeReplacementNode; - - if (typeof nodeName != 'function') { - var stencilNode = nodeName.nodeType ? nodeName : doc.createElement(nodeName); - - makeReplacementNode = function(fill, matchIndex) { - var clone = stencilNode.cloneNode(false); - - clone.setAttribute('data-mce-index', matchIndex); - - if (fill) { - clone.appendChild(doc.createTextNode(fill)); - } - - return clone; - }; - } else { - makeReplacementNode = nodeName; - } - - return function replace(range) { - var before, after, parentNode, startNode = range.startNode, - endNode = range.endNode, matchIndex = range.matchIndex; - - if (startNode === endNode) { - var node = startNode; - - parentNode = node.parentNode; - if (range.startNodeIndex > 0) { - // Add `before` text node (before the match) - before = doc.createTextNode(node.data.substring(0, range.startNodeIndex)); - parentNode.insertBefore(before, node); - } - - // Create the replacement node: - var el = makeReplacementNode(range.match[0], matchIndex); - parentNode.insertBefore(el, node); - if (range.endNodeIndex < node.length) { - // Add `after` text node (after the match) - after = doc.createTextNode(node.data.substring(range.endNodeIndex)); - parentNode.insertBefore(after, node); - } - - node.parentNode.removeChild(node); - - return el; - } else { - // Replace startNode -> [innerNodes...] -> endNode (in that order) - before = doc.createTextNode(startNode.data.substring(0, range.startNodeIndex)); - after = doc.createTextNode(endNode.data.substring(range.endNodeIndex)); - var elA = makeReplacementNode(startNode.data.substring(range.startNodeIndex), matchIndex); - var innerEls = []; - - for (var i = 0, l = range.innerNodes.length; i < l; ++i) { - var innerNode = range.innerNodes[i]; - var innerEl = makeReplacementNode(innerNode.data, matchIndex); - innerNode.parentNode.replaceChild(innerEl, innerNode); - innerEls.push(innerEl); - } - - var elB = makeReplacementNode(endNode.data.substring(0, range.endNodeIndex), matchIndex); - - parentNode = startNode.parentNode; - parentNode.insertBefore(before, startNode); - parentNode.insertBefore(elA, startNode); - parentNode.removeChild(startNode); - - parentNode = endNode.parentNode; - parentNode.insertBefore(elB, endNode); - parentNode.insertBefore(after, endNode); - parentNode.removeChild(endNode); - - return elB; - } - }; - } - - text = getText(node); - if (text && regex.global) { - while ((m = regex.exec(text))) { - matches.push(getMatchIndexes(m)); - } - } - - function filter(callback) { - var filteredMatches = []; - - each(function(match, i) { - if (callback(match, i)) { - filteredMatches.push(match); - } - }); - - matches = filteredMatches; - - /*jshint validthis:true*/ - return this; - } - - function each(callback) { - for (var i = 0, l = matches.length; i < l; i++) { - if (callback(matches[i], i) === false) { - break; - } - } - - /*jshint validthis:true*/ - return this; - } - - function mark(replacementNode) { - if (matches.length) { - count = matches.length; - stepThroughMatches(node, matches, genReplacer(replacementNode)); - } - - /*jshint validthis:true*/ - return this; - } - - return { - text: text, - count: count, - matches: matches, - each: each, - filter: filter, - mark: mark - }; - }; -}); - -// Included from: js/tinymce/plugins/spellchecker/classes/Plugin.js - -/** - * Plugin.js - * - * Copyright, Moxiecode Systems AB - * Released under LGPL License. - * - * License: http://www.tinymce.com/license - * Contributing: http://www.tinymce.com/contributing - */ - -/*jshint camelcase:false */ - -/** - * This class contains all core logic for the spellchecker plugin. - * - * @class tinymce.spellcheckerplugin.Plugin - * @private - */ -define("tinymce/spellcheckerplugin/Plugin", [ - "tinymce/spellcheckerplugin/DomTextMatcher", - "tinymce/PluginManager", - "tinymce/util/Tools", - "tinymce/ui/Menu", - "tinymce/dom/DOMUtils", - "tinymce/util/JSONRequest", - "tinymce/util/URI" -], function(DomTextMatcher, PluginManager, Tools, Menu, DOMUtils, JSONRequest, URI) { - PluginManager.add('spellchecker', function(editor, url) { - var lastSuggestions, started, suggestionsMenu, settings = editor.settings; - - function isEmpty(obj) { - /*jshint unused:false*/ - for (var name in obj) { - return false; - } - - return true; - } - - function showSuggestions(target, word) { - var items = [], suggestions = lastSuggestions[word]; - - Tools.each(suggestions, function(suggestion) { - items.push({ - text: suggestion, - onclick: function() { - editor.insertContent(suggestion); - checkIfFinished(); - } - }); - }); - - items.push.apply(items, [ - {text: '-'}, - - {text: 'Ignore', onclick: function() { - ignoreWord(target, word); - }}, - - {text: 'Ignore all', onclick: function() { - ignoreWord(target, word, true); - }}, - - {text: 'Finish', onclick: finish} - ]); - - // Render menu - suggestionsMenu = new Menu({ - items: items, - context: 'contextmenu', - onautohide: function(e) { - if (e.target.className.indexOf('spellchecker') != -1) { - e.preventDefault(); - } - }, - onhide: function() { - suggestionsMenu.remove(); - suggestionsMenu = null; - } - }); - - suggestionsMenu.renderTo(document.body); - - // Position menu - var pos = DOMUtils.DOM.getPos(editor.getContentAreaContainer()); - var targetPos = editor.dom.getPos(target); - - pos.x += targetPos.x; - pos.y += targetPos.y; - - suggestionsMenu.moveTo(pos.x, pos.y + target.offsetHeight); - } - - function spellcheck() { - var textFilter, words = [], uniqueWords = {}; - - if (started) { - finish(); - return; - } - - started = true; - - function doneCallback(suggestions) { - editor.setProgressState(false); - - if (isEmpty(suggestions)) { - editor.windowManager.alert('No misspellings found'); - started = false; - return; - } - - lastSuggestions = suggestions; - - textFilter.filter(function(match) { - return !!suggestions[match[2][0]]; - }).mark(editor.dom.create('span', { - "class": 'mce-spellchecker-word', - "data-mce-bogus": 1 - })); - - textFilter = null; - editor.fire('SpellcheckStart'); - } - - // Regexp for finding word specific characters this will split words by - // spaces, quotes, copy right characters etc. It's escaped with unicode characters - // to make it easier to output scripts on servers using different encodings - // so if you add any characters outside the 128 byte range make sure to escape it - var nonWordSeparatorCharacters = editor.getParam('spellchecker_wordchar_pattern') || new RegExp("[^" + - "\\s!\"#$%&()*+,-./:;<=>?@[\\]^_{|}`" + - "\u00a7\u00a9\u00ab\u00ae\u00b1\u00b6\u00b7\u00b8\u00bb" + - "\u00bc\u00bd\u00be\u00bf\u00d7\u00f7\u00a4\u201d\u201c\u201e" + - "]+", "g"); - - // Find all words and make an unique words array - textFilter = new DomTextMatcher(nonWordSeparatorCharacters, editor.getBody(), editor.schema).each(function(match) { - var word = match[2][0]; - - // TODO: Fix so it remembers correctly spelled words - if (!uniqueWords[word]) { - // Ignore numbers and single character words - if (/^\d+$/.test(word) || word.length == 1) { - return; - } - - words.push(word); - uniqueWords[word] = true; - } - }); - - function defaultSpellcheckCallback(method, words, doneCallback) { - JSONRequest.sendRPC({ - url: new URI(url).toAbsolute(settings.spellchecker_rpc_url), - method: method, - params: { - lang: settings.spellchecker_language || "en", - words: words - }, - success: function(result) { - doneCallback(result); - }, - error: function(error, xhr) { - if (error == "JSON Parse error.") { - error = "Non JSON response:" + xhr.responseText; - } else { - error = "Error: " + error; - } - - editor.windowManager.alert(error); - editor.setProgressState(false); - textFilter = null; - started = false; - } - }); - } - - editor.setProgressState(true); - - var spellCheckCallback = settings.spellchecker_callback || defaultSpellcheckCallback; - spellCheckCallback("spellcheck", words, doneCallback); - } - - function checkIfFinished() { - if (!editor.dom.select('span.mce-spellchecker-word').length) { - finish(); - } - } - - function unwrap(node) { - var parentNode = node.parentNode; - parentNode.insertBefore(node.firstChild, node); - node.parentNode.removeChild(node); - } - - function ignoreWord(target, word, all) { - if (all) { - Tools.each(editor.dom.select('span.mce-spellchecker-word'), function(item) { - var text = item.innerText || item.textContent; - - if (text == word) { - unwrap(item); - } - }); - } else { - unwrap(target); - } - - checkIfFinished(); - } - - function finish() { - var i, nodes, node; - - started = false; - node = editor.getBody(); - nodes = node.getElementsByTagName('span'); - i = nodes.length; - while (i--) { - node = nodes[i]; - if (node.getAttribute('data-mce-index')) { - unwrap(node); - } - } - - editor.fire('SpellcheckEnd'); - } - - function selectMatch(index) { - var nodes, i, spanElm, spanIndex = -1, startContainer, endContainer; - - index = "" + index; - nodes = editor.getBody().getElementsByTagName("span"); - for (i = 0; i < nodes.length; i++) { - spanElm = nodes[i]; - if (spanElm.className == "mce-spellchecker-word") { - spanIndex = spanElm.getAttribute('data-mce-index'); - if (spanIndex === index) { - spanIndex = index; - - if (!startContainer) { - startContainer = spanElm.firstChild; - } - - endContainer = spanElm.firstChild; - } - - if (spanIndex !== index && endContainer) { - break; - } - } - } - - var rng = editor.dom.createRng(); - rng.setStart(startContainer, 0); - rng.setEnd(endContainer, endContainer.length); - editor.selection.setRng(rng); - - return rng; - } - - editor.on('click', function(e) { - if (e.target.className == "mce-spellchecker-word") { - e.preventDefault(); - - var rng = selectMatch(e.target.getAttribute('data-mce-index')); - showSuggestions(e.target, rng.toString()); - } - }); - - editor.addMenuItem('spellchecker', { - text: 'Spellcheck', - context: 'tools', - onclick: spellcheck, - selectable: true, - onPostRender: function() { - var self = this; - - editor.on('SpellcheckStart SpellcheckEnd', function() { - self.active(started); - }); - } - }); - - editor.addButton('spellchecker', { - tooltip: 'Spellcheck', - onclick: spellcheck, - onPostRender: function() { - var self = this; - - editor.on('SpellcheckStart SpellcheckEnd', function() { - self.active(started); - }); - } - }); - - editor.on('remove', function() { - if (suggestionsMenu) { - suggestionsMenu.remove(); - suggestionsMenu = null; - } - }); - }); -}); - -expose(["tinymce/spellcheckerplugin/DomTextMatcher","tinymce/spellcheckerplugin/Plugin"]); -})(this); \ No newline at end of file diff --git a/wp-includes/js/tinymce/plugins/spellchecker/plugin.min.js b/wp-includes/js/tinymce/plugins/spellchecker/plugin.min.js deleted file mode 100644 index 2e40b272b7..0000000000 --- a/wp-includes/js/tinymce/plugins/spellchecker/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e,t){"use strict";function n(e,t){for(var n,r=[],o=0;o=s[1]?(o=d,a=s[1]-l):r&&c.push(d),!r&&d.length+l>s[0]&&(r=d,i=s[0]-l),l+=d.length),r&&o){if(d=n({startNode:r,startNodeIndex:i,endNode:o,endNodeIndex:a,innerNodes:c,match:s[2],matchIndex:u}),l-=o.length-a,r=null,o=null,c=[],s=t.shift(),u++,!s)break}else{if((!m[d.nodeName]||p[d.nodeName])&&d.firstChild){d=d.firstChild;continue}if(d.nextSibling){d=d.nextSibling;continue}}for(;;){if(d.nextSibling){d=d.nextSibling;break}if(d.parentNode===e)break e;d=d.parentNode}}}function a(e){var t;if("function"!=typeof e){var n=e.nodeType?e:g.createElement(e);t=function(e,t){var r=n.cloneNode(!1);return r.setAttribute("data-mce-index",t),e&&r.appendChild(g.createTextNode(e)),r}}else t=e;return function r(e){var n,r,o,i=e.startNode,a=e.endNode,c=e.matchIndex;if(i===a){var l=i;o=l.parentNode,e.startNodeIndex>0&&(n=g.createTextNode(l.data.substring(0,e.startNodeIndex)),o.insertBefore(n,l));var d=t(e.match[0],c);return o.insertBefore(d,l),e.endNodeIndexf;++f){var p=e.innerNodes[f],m=t(p.data,c);p.parentNode.replaceChild(m,p),u.push(m)}var v=t(a.data.substring(0,e.endNodeIndex),c);return o=i.parentNode,o.insertBefore(n,i),o.insertBefore(s,i),o.removeChild(i),o=a.parentNode,o.insertBefore(v,a),o.insertBefore(r,a),o.removeChild(a),v}}function c(e){var t=[];return l(function(n,r){e(n,r)&&t.push(n)}),u=t,this}function l(e){for(var t=0,n=u.length;n>t&&e(u[t],t)!==!1;t++);return this}function d(e){return u.length&&(h=u.length,i(t,u,a(e))),this}var s,u=[],f,h=0,g,p,m,v;if(g=t.ownerDocument,p=n.getBlockElements(),m=n.getWhiteSpaceElements(),v=n.getShortEndedElements(),f=o(t),f&&e.global)for(;s=e.exec(f);)u.push(r(s));return{text:f,count:h,matches:u,each:l,filter:c,mark:d}}}),r(d,[l,s,u,f,h,g,p],function(e,t,n,r,o,i,a){t.add("spellchecker",function(t,c){function l(e){for(var t in e)return!1;return!0}function d(e,i){var a=[],c=m[i];n.each(c,function(e){a.push({text:e,onclick:function(){t.insertContent(e),u()}})}),a.push.apply(a,[{text:"-"},{text:"Ignore",onclick:function(){h(e,i)}},{text:"Ignore all",onclick:function(){h(e,i,!0)}},{text:"Finish",onclick:g}]),N=new r({items:a,context:"contextmenu",onautohide:function(e){-1!=e.target.className.indexOf("spellchecker")&&e.preventDefault()},onhide:function(){N.remove(),N=null}}),N.renderTo(document.body);var l=o.DOM.getPos(t.getContentAreaContainer()),d=t.dom.getPos(e);l.x+=d.x,l.y+=d.y,N.moveTo(l.x,l.y+e.offsetHeight)}function s(){function n(e){return t.setProgressState(!1),l(e)?(t.windowManager.alert("No misspellings found"),v=!1,void 0):(m=e,o.filter(function(t){return!!e[t[2][0]]}).mark(t.dom.create("span",{"class":"mce-spellchecker-word","data-mce-bogus":1})),o=null,t.fire("SpellcheckStart"),void 0)}function r(e,n,r){i.sendRPC({url:new a(c).toAbsolute(x.spellchecker_rpc_url),method:e,params:{lang:x.spellchecker_language||"en",words:n},success:function(e){r(e)},error:function(e,n){e="JSON Parse error."==e?"Non JSON response:"+n.responseText:"Error: "+e,t.windowManager.alert(e),t.setProgressState(!1),o=null,v=!1}})}var o,d=[],s={};if(v)return g(),void 0;v=!0;var u=t.getParam("spellchecker_wordchar_pattern")||new RegExp('[^\\s!"#$%&()*+,-./:;<=>?@[\\]^_{|}`\xa7\xa9\xab\xae\xb1\xb6\xb7\xb8\xbb\xbc\xbd\xbe\xbf\xd7\xf7\xa4\u201d\u201c\u201e]+',"g");o=new e(u,t.getBody(),t.schema).each(function(e){var t=e[2][0];if(!s[t]){if(/^\d+$/.test(t)||1==t.length)return;d.push(t),s[t]=!0}}),t.setProgressState(!0);var f=x.spellchecker_callback||r;f("spellcheck",d,n)}function u(){t.dom.select("span.mce-spellchecker-word").length||g()}function f(e){var t=e.parentNode;t.insertBefore(e.firstChild,e),e.parentNode.removeChild(e)}function h(e,r,o){o?n.each(t.dom.select("span.mce-spellchecker-word"),function(e){var t=e.innerText||e.textContent;t==r&&f(e)}):f(e),u()}function g(){var e,n,r;for(v=!1,r=t.getBody(),n=r.getElementsByTagName("span"),e=n.length;e--;)r=n[e],r.getAttribute("data-mce-index")&&f(r);t.fire("SpellcheckEnd")}function p(e){var n,r,o,i=-1,a,c;for(e=""+e,n=t.getBody().getElementsByTagName("span"),r=0;rdecode($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"}}'); - die('{"error":"You must choose spellchecker engine in the config.php file."}'); -} -// 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); - -?> diff --git a/wp-includes/js/tinymce/wp-tinymce.js.gz b/wp-includes/js/tinymce/wp-tinymce.js.gz index 49eb693792a53680d102c43fa607676b397c5909..3e3c9abd66c2806cbad42bba4bdfe2854fc3f6f4 100644 GIT binary patch delta 11931 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 delta 14160 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 acWz}B