fixed: Server side spellchecker doesn't work
This commit is contained in:
parent
26cc8ad9df
commit
2b8d9a7b48
9 changed files with 559 additions and 154 deletions
|
|
@ -18,6 +18,7 @@
|
|||
- fixed: DEmote in toolbar menu has PROmote url
|
||||
- fixed: EMS purge now functions correctly
|
||||
- improve behavior of preload.perl for custom lib dirs not ending in lib
|
||||
- fixed: Server side spellchecker doesn't work
|
||||
|
||||
7.5.18
|
||||
- fixed: Collateral Image Manager broken in Firefox 3
|
||||
|
|
|
|||
|
|
@ -20,9 +20,6 @@ use WebGUI::Form;
|
|||
use WebGUI::Utility;
|
||||
use WebGUI::International;
|
||||
use JSON;
|
||||
BEGIN {
|
||||
eval { require Text::Aspell }; # Optional
|
||||
}
|
||||
|
||||
our @ISA = qw(WebGUI::Asset);
|
||||
|
||||
|
|
@ -494,7 +491,9 @@ sub getRichEditor {
|
|||
);
|
||||
foreach my $button (@toolbarButtons) {
|
||||
if ($button eq "spellchecker" && $self->session->config->get('availableDictionaries')) {
|
||||
push(@plugins,"spellchecker");
|
||||
push(@plugins,"-wgspellchecker");
|
||||
$loadPlugins{wgspellchecker} = $self->session->url->extras("tinymce-webgui/plugins/wgspellchecker/editor_plugin.js");
|
||||
$config{spellchecker_rpc_url} = $self->session->url->gateway('', "op=spellCheck");
|
||||
$config{spellchecker_languages} =
|
||||
join(',', map { ($_->{default} ? '+' : '').$_->{name}.'='.$_->{id} } @{$self->session->config->get('availableDictionaries')});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,21 @@ package WebGUI::Operation::SpellCheck;
|
|||
#-------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use Encode;
|
||||
# Optional, but if unavailable, spell checking will have no effect.
|
||||
eval 'use Text::Aspell';
|
||||
use WebGUI::Utility;
|
||||
use File::Path qw(mkpath);
|
||||
# Optional, but if unavailable, spell checking will have no effect.
|
||||
my $spellerAvailable;
|
||||
BEGIN {
|
||||
eval {
|
||||
require Text::Aspell;
|
||||
};
|
||||
$spellerAvailable = 1
|
||||
unless $@;
|
||||
};
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Operation::Spellcheck
|
||||
Package WebGUI::Operation::SpellCheck
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
|
@ -28,7 +35,7 @@ Operation for server side spellchecking functions.
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 _getSpeller ( session )
|
||||
=head2 _getSpeller ( session , language )
|
||||
|
||||
Returns an instanciated Text::Aspell object.
|
||||
|
||||
|
|
@ -36,99 +43,145 @@ Returns an instanciated Text::Aspell object.
|
|||
|
||||
An instanciated session object.
|
||||
|
||||
=head3 language
|
||||
|
||||
The language code to use for spell checking.
|
||||
|
||||
=cut
|
||||
|
||||
sub _getSpeller {
|
||||
my ($baseDir, $userDir, $homeDir);
|
||||
my $session = shift;
|
||||
return undef unless Text::Aspell->can('new');
|
||||
my $speller = Text::Aspell->new;
|
||||
my $session = shift;
|
||||
my $lang = shift;
|
||||
die "Server side spellcheck not available\n"
|
||||
unless $spellerAvailable;
|
||||
# Get language
|
||||
my $speller = Text::Aspell->new;
|
||||
die "Language not available in server side spellcheck"
|
||||
unless (isIn($lang, map {m/^.*?:([^:]*):.*?$/} $speller->list_dictionaries));
|
||||
|
||||
# Get language
|
||||
my $lang = $session->form->process('lang');
|
||||
return undef unless (isIn($lang, map {m/^.*?:([^:]*):.*?$/} $speller->list_dictionaries));
|
||||
# User homedir
|
||||
my $homeDir = $session->config->get('uploadsPath').'/dictionaries/';
|
||||
|
||||
# User homedir
|
||||
my $userId = $session->user->userId;
|
||||
my $userId = $session->user->userId;
|
||||
if (length($userId) < 22) {
|
||||
$homeDir .= "oldIds/$userId";
|
||||
}
|
||||
else {
|
||||
$userId =~ m/^(.{2})(.{2})/;
|
||||
$homeDir .= "$1/$2/$userId";
|
||||
}
|
||||
mkpath($homeDir) unless (-e $homeDir);
|
||||
|
||||
$baseDir = $session->config->get('uploadsPath').'/dictionaries/';
|
||||
|
||||
if (length($userId) < 22) {
|
||||
$userDir = 'oldIds/'.$userId;
|
||||
|
||||
mkdir($baseDir.$userDir) unless (-e $baseDir.$userDir);
|
||||
} else {
|
||||
$userDir = $userId;
|
||||
$userDir =~ s/^(.{2})(.{2})*$/$1\/$2\/$userId/;
|
||||
|
||||
mkdir($baseDir.$1) unless (-e $baseDir.$1);
|
||||
mkdir($baseDir.$1.'/'.$2) unless (-e $baseDir.$1.'/'.$2);
|
||||
}
|
||||
|
||||
$homeDir = $baseDir.$userDir;
|
||||
|
||||
mkdir($homeDir) unless (-e $homeDir);
|
||||
|
||||
# Set speller options.
|
||||
$speller->set_option('home-dir', $homeDir);
|
||||
$speller->set_option('lang', $lang);
|
||||
|
||||
return $speller;
|
||||
# Set speller options.
|
||||
$speller->set_option('home-dir', $homeDir);
|
||||
$speller->set_option('lang', $lang);
|
||||
return $speller;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 _processOutput ( session, words, [ id, [ command ] ] )
|
||||
=head2 addWord ( $session, $language, $word )
|
||||
|
||||
Processes the wordlist and generates an XML string that the TinyMCE spellchecker
|
||||
plugin can grok.
|
||||
Adds a word sent by the tinymce spellchecker plugin to the personal dictionary
|
||||
of the the current user.
|
||||
|
||||
=head3 session
|
||||
=head3 $session
|
||||
|
||||
The instanciated session object.
|
||||
The instanciated session object
|
||||
|
||||
=head3 words
|
||||
=head3 $language
|
||||
|
||||
An arrayref containing the words that you want to send back to the spellchecker
|
||||
plugin.
|
||||
The dictionary language to use.
|
||||
|
||||
=head3 id
|
||||
=head3 $word
|
||||
|
||||
The id that the tinyMCE spellchecker plugin assigined to this specific action.
|
||||
If not specified the value of the formparam 'id' will be sent.
|
||||
|
||||
=head3 command
|
||||
|
||||
The spellchecker plugin command that has been issued. If omitted the value of
|
||||
formparam 'cmd' will be used.
|
||||
The word to add to the dictionary.
|
||||
|
||||
=cut
|
||||
|
||||
sub _processOutput {
|
||||
my $session = shift;
|
||||
my $words = shift || [];
|
||||
my $id = shift || $session->form->process('id');
|
||||
my $command = shift || $session->form->process('cmd');
|
||||
|
||||
$session->http->setMimeType('text/xml; charset=utf-8');
|
||||
my $output = '<?xml version="1.0" encoding="utf-8" ?>'."\n";
|
||||
sub addWord {
|
||||
my $session = shift;
|
||||
my $language = shift;
|
||||
my $word = shift;
|
||||
die "You must be logged in to add words to your dictionary.\n:"
|
||||
if ($session->user->userId eq '1');
|
||||
my $speller = _getSpeller($session, $language);
|
||||
$speller->add_to_personal($word);
|
||||
$speller->save_all_word_lists;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (scalar(@$words) == 0) {
|
||||
$output .= '<res id="'.$id.'" cmd="'.$command.'"></res>';
|
||||
}
|
||||
else {
|
||||
$output .= '<res id="'.$id.'" cmd="'.$command.'">'.encode_utf8(join(" ", @$words)).'</res>';
|
||||
}
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
return $output;
|
||||
=head2 checkWords ( $session, $language, \@words )
|
||||
|
||||
Check the spelling on a list of words and returns a list of misspelled words as an array reference
|
||||
|
||||
=head3 $session
|
||||
|
||||
The instanciated session object
|
||||
|
||||
=head3 $language
|
||||
|
||||
The dictionary language to use.
|
||||
|
||||
=head3 \@word
|
||||
|
||||
The words to check the spelling of as an array reference.
|
||||
|
||||
=cut
|
||||
|
||||
sub checkWords {
|
||||
my $session = shift;
|
||||
my $language = shift;
|
||||
my $words = shift;
|
||||
my $speller = _getSpeller($session, $language);
|
||||
my @result;
|
||||
foreach my $word (@$words) {
|
||||
unless ($speller->check($word)) {
|
||||
push(@result, $word);
|
||||
}
|
||||
}
|
||||
return \@result;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getSuggestions ( $session, $language, $word )
|
||||
|
||||
Returns a list of suggested words for a misspelled word sent by the
|
||||
tinyMCE spellchecker as an array reference.
|
||||
|
||||
=head3 $session
|
||||
|
||||
The instanciated session object.
|
||||
|
||||
=head3 $language
|
||||
|
||||
The dictionary language to use.
|
||||
|
||||
=head3 $word
|
||||
|
||||
The misspelled word to get suggestions for.
|
||||
|
||||
=cut
|
||||
|
||||
sub getSuggestions {
|
||||
my $session = shift;
|
||||
my $language = shift;
|
||||
my $word = shift;
|
||||
my $speller = _getSpeller($session, $language);
|
||||
my @result = $speller->suggest($word);
|
||||
return \@result;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_spellCheck ( session )
|
||||
|
||||
Fetches the the text to be checked as sent by the tinyMCE spellchecker and
|
||||
returns a list of erroneous words in the correct XML format.
|
||||
Fetches the JSON data sent by the TinyMCE spell checker and dispatches
|
||||
to the correct sub to handle each request type. Encodes the result
|
||||
as a JSON string to be sent back to the client.
|
||||
|
||||
=head3 session
|
||||
|
||||
|
|
@ -137,87 +190,37 @@ The instanciated session object.
|
|||
=cut
|
||||
|
||||
sub www_spellCheck {
|
||||
my $session = shift;
|
||||
my (@result, $output);
|
||||
my $session = shift;
|
||||
# JSON data is sent directly as POST data, read it into a scalar then decode
|
||||
my $data = '';
|
||||
while ($session->request->read(my $buffer, 1024)) {
|
||||
$data .= $buffer;
|
||||
}
|
||||
my $params = JSON->new->utf8->decode($data);
|
||||
|
||||
my $speller = _getSpeller($session);
|
||||
return _processOutput($session) unless (defined($speller));
|
||||
|
||||
# Set speller options?
|
||||
|
||||
# Get form params
|
||||
my $check = $session->form->process('check');
|
||||
my $command = $session->form->process('cmd');
|
||||
my $language = $session->form->process('lang');
|
||||
my $mode = $session->form->process('mode');
|
||||
my $id = $session->form->process('id');
|
||||
|
||||
# Check it!
|
||||
my @words = split(/\s/, $check);
|
||||
|
||||
foreach my $word (@words) {
|
||||
unless ($speller->check($word)) {
|
||||
push(@result, $word);
|
||||
}
|
||||
}
|
||||
|
||||
return _processOutput($session, \@result);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_suggestWords ( session )
|
||||
|
||||
Returns a list of suggested words in the correct XML format for a misspelled
|
||||
word sent by the tinyMCE spellchecker.
|
||||
|
||||
=head3 session
|
||||
|
||||
The instanciated session object.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_suggestWords {
|
||||
my $session = shift;
|
||||
|
||||
my $speller = _getSpeller($session);
|
||||
return _processOutput($session) unless (defined($speller));
|
||||
my $check = $session->form->process('check');
|
||||
|
||||
my @result = $speller->suggest($check);
|
||||
|
||||
return _processOutput($session, \@result);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_addWordToDictionary ( session )
|
||||
|
||||
Adds a word sent by the tinymce spellchecker plugin to the personal dictionary
|
||||
of the the current user.
|
||||
|
||||
=head3 session
|
||||
|
||||
The instanciated session object
|
||||
|
||||
=cut
|
||||
|
||||
sub www_addWordToDictionary {
|
||||
my $session = shift;
|
||||
|
||||
# Visitors do not have a personal dictionary
|
||||
return _processOutput($session, ['You must be logged in to add words to your dictionary.']) if ($session->user->userId eq '1');
|
||||
|
||||
my $speller = _getSpeller($session);
|
||||
return _processOutput($session) unless (defined($speller));
|
||||
my $check = $session->form->process('check');
|
||||
|
||||
if ($check) {
|
||||
$speller->add_to_personal($check);
|
||||
$speller->save_all_word_lists;
|
||||
}
|
||||
|
||||
return _processOutput($session);
|
||||
my $result;
|
||||
# dispatch to different subs based on the 'method' in the JSON data
|
||||
my %dispatch = (
|
||||
checkWords => \&checkWords,
|
||||
getSuggestions => \&getSuggestions,
|
||||
addWord => \&addWord,
|
||||
);
|
||||
if (exists $dispatch{$params->{method}}) {
|
||||
eval {
|
||||
# get results from sub and build result data
|
||||
$result = { result => $dispatch{$params->{method}}->($session, @{ $params->{params} }) };
|
||||
};
|
||||
if ($@) {
|
||||
$result = {error => {errstr => $@}};
|
||||
}
|
||||
}
|
||||
else {
|
||||
$result = {error => {errstr => "Invalid request"}};
|
||||
}
|
||||
# add request id and send to client as JSON blob
|
||||
$result->{id} = $params->{id};
|
||||
$session->http->setMimeType("text/plain; charset=utf-8");
|
||||
return JSON->new->encode($result);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
diff --git a/editor_plugin_src.js b/editor_plugin_src.js
|
||||
index 4e9ba99..a96e310 100644
|
||||
--- a/editor_plugin_src.js
|
||||
+++ b/editor_plugin_src.js
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
(function() {
|
||||
var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM;
|
||||
+ tinymce.PluginManager.requireLangPack('wgspellchecker');
|
||||
|
||||
tinymce.create('tinymce.plugins.SpellcheckerPlugin', {
|
||||
getInfo : function() {
|
||||
@@ -269,6 +270,16 @@
|
||||
}
|
||||
});
|
||||
|
||||
+ m.add({
|
||||
+ title : 'spellchecker.add_word',
|
||||
+ onclick : function() {
|
||||
+ t._sendRPC('addWord', [t.selectedLang, dom.decode(e.target.innerHTML)], function(r) {
|
||||
+ t._removeWords(dom.decode(e.target.innerHTML));
|
||||
+ t._checkDone();
|
||||
+ });
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
m.update();
|
||||
});
|
||||
|
||||
@@ -333,5 +344,5 @@
|
||||
});
|
||||
|
||||
// Register plugin
|
||||
- tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin);
|
||||
-})();
|
||||
\ No newline at end of file
|
||||
+ tinymce.PluginManager.add('wgspellchecker', tinymce.plugins.SpellcheckerPlugin);
|
||||
+})();
|
||||
diff --git a/dev/null b/langs/en.js
|
||||
new file mode 100644
|
||||
index 0000000..602b23c
|
||||
--- /dev/null
|
||||
+++ b/langs/en.js
|
||||
@@ -0,0 +1,4 @@
|
||||
+tinyMCE.addI18n('en.spellchecker',{
|
||||
+ add_word : 'Add word to dictionary'
|
||||
+});
|
||||
+
|
||||
|
|
@ -0,0 +1 @@
|
|||
.mceItemHiddenSpellWord {background:url(../img/wline.gif) repeat-x bottom left; cursor:default;}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,348 @@
|
|||
/**
|
||||
* $Id: editor_plugin_src.js 425 2007-11-21 15:17:39Z spocke $
|
||||
*
|
||||
* @author Moxiecode
|
||||
* @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM;
|
||||
tinymce.PluginManager.requireLangPack('wgspellchecker');
|
||||
|
||||
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;
|
||||
|
||||
// Register commands
|
||||
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() {
|
||||
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();
|
||||
});
|
||||
|
||||
// Find selected language
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
// Internal functions
|
||||
|
||||
_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');
|
||||
|
||||
// Build word separator regexp
|
||||
for (i=0; i<str.length; i++)
|
||||
re += '\\' + str.charAt(i);
|
||||
|
||||
return re;
|
||||
},
|
||||
|
||||
_getWords : function() {
|
||||
var ed = this.editor, wl = [], tx = '', lo = {};
|
||||
|
||||
// Get area text
|
||||
this._walk(ed.getBody(), function(n) {
|
||||
if (n.nodeType == 3)
|
||||
tx += n.nodeValue + ' ';
|
||||
});
|
||||
|
||||
// Split words by separator
|
||||
tx = tx.replace(new RegExp('([0-9]|[' + this._getSeparators() + '])', 'g'), ' ');
|
||||
tx = tinymce.trim(tx.replace(/(\s+)/g, ' '));
|
||||
|
||||
// Build word array and remove duplicates
|
||||
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');
|
||||
|
||||
// Collect all text nodes
|
||||
this._walk(this.editor.getBody(), function(n) {
|
||||
if (n.nodeType == 3) {
|
||||
nl.push(n);
|
||||
}
|
||||
});
|
||||
|
||||
// Wrap incorrect words in spans
|
||||
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());
|
||||
//p2 = DOM.getPos(ed.getContainer());
|
||||
|
||||
m = ed.controlManager.createDropMenu('spellcheckermenu', {
|
||||
offset_x : p1.x,
|
||||
offset_y : p1.y,
|
||||
'class' : 'noIcons'
|
||||
});
|
||||
|
||||
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.add({
|
||||
title : 'spellchecker.add_word',
|
||||
onclick : function() {
|
||||
t._sendRPC('addWord', [t.selectedLang, dom.decode(e.target.innerHTML)], function(r) {
|
||||
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));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Register plugin
|
||||
tinymce.PluginManager.add('wgspellchecker', tinymce.plugins.SpellcheckerPlugin);
|
||||
})();
|
||||
BIN
www/extras/tinymce-webgui/plugins/wgspellchecker/img/wline.gif
Normal file
BIN
www/extras/tinymce-webgui/plugins/wgspellchecker/img/wline.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 B |
|
|
@ -0,0 +1,4 @@
|
|||
tinyMCE.addI18n('en.spellchecker',{
|
||||
add_word : 'Add word to dictionary'
|
||||
});
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue