2013-10-03 01:02:52 +00:00
|
|
|
define([
|
|
|
|
"jquery",
|
|
|
|
"underscore",
|
2013-10-04 00:34:58 +00:00
|
|
|
"crel",
|
2013-10-03 01:02:52 +00:00
|
|
|
"utils",
|
|
|
|
"classes/Extension",
|
|
|
|
"xregexp",
|
2013-10-05 01:30:54 +00:00
|
|
|
"text!bower-libs/Typo.js/typo/typo.js",
|
2013-10-09 01:16:49 +00:00
|
|
|
"text!bower-libs/lz-string/libs/lz-string-1.3.3.js",
|
2013-10-05 01:30:54 +00:00
|
|
|
"text!workers/spellCheckWorker.js",
|
2013-10-09 01:16:49 +00:00
|
|
|
"text!html/spellCheckSettingsBlock.html",
|
|
|
|
], function($, _, crel, utils, Extension, XRegExp, typoJS, LZStringJS, spellCheckWorkerJS, spellCheckSettingsBlockHTML) {
|
2013-10-03 01:02:52 +00:00
|
|
|
|
2013-10-05 01:30:54 +00:00
|
|
|
var spellCheck = new Extension("spellCheck", "Spell Check", true, true, true);
|
2013-10-09 01:16:49 +00:00
|
|
|
spellCheck.settingsBlock = spellCheckSettingsBlockHTML;
|
|
|
|
spellCheck.defaultConfig = {
|
|
|
|
locale: "en_US",
|
|
|
|
};
|
|
|
|
|
|
|
|
spellCheck.onLoadSettings = function() {
|
|
|
|
utils.setInputValue("#select-spell-check-locale", spellCheck.config.locale);
|
|
|
|
};
|
|
|
|
|
|
|
|
spellCheck.onSaveSettings = function(newConfig, event) {
|
|
|
|
newConfig.locale = utils.getInputValue("#select-spell-check-locale");
|
|
|
|
};
|
2013-10-03 01:02:52 +00:00
|
|
|
|
2013-10-05 01:30:54 +00:00
|
|
|
// Create a web worker
|
|
|
|
var worker = new Worker('res/worker.js');
|
|
|
|
worker.postMessage(spellCheckWorkerJS);
|
2013-10-09 01:16:49 +00:00
|
|
|
|
|
|
|
var isInited = false;
|
|
|
|
spellCheck.onInit = function() {
|
|
|
|
require([
|
|
|
|
'text!../libs/dictionaries/' + spellCheck.config.locale + '.dic.lz',
|
|
|
|
'text!../libs/dictionaries/' + spellCheck.config.locale + '.aff.lz',
|
|
|
|
], function(dic, aff) {
|
|
|
|
worker.postMessage(JSON.stringify(['init', typoJS, LZStringJS, spellCheck.config.locale, aff, dic]));
|
|
|
|
isInited = true;
|
|
|
|
start();
|
|
|
|
});
|
|
|
|
};
|
2013-10-05 01:30:54 +00:00
|
|
|
|
2013-10-03 01:02:52 +00:00
|
|
|
var aceEditor = undefined;
|
2013-10-06 14:34:40 +00:00
|
|
|
var wordRegExp = XRegExp('\\p{L}+(?:\'\\p{L}+)*', 'g');
|
2013-10-04 00:34:58 +00:00
|
|
|
var markers = [];
|
2013-10-05 01:30:54 +00:00
|
|
|
var timeoutId = undefined;
|
2013-10-09 01:16:49 +00:00
|
|
|
|
2013-10-05 01:30:54 +00:00
|
|
|
var currentRowCheck = undefined;
|
2013-10-09 01:16:49 +00:00
|
|
|
|
2013-10-05 01:30:54 +00:00
|
|
|
function rowCheck(rowIndex) {
|
|
|
|
var tokens = aceEditor.session.getTokens(rowIndex).slice();
|
|
|
|
var tokenOffset = 0;
|
|
|
|
var self = this;
|
|
|
|
self.checkToken = function() {
|
|
|
|
if (tokens.length === 0) {
|
|
|
|
!timeoutId && (timeoutId = setTimeout(check, 5));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var token = tokens.shift();
|
|
|
|
var words = [];
|
|
|
|
if (!/code|code_block|reference|markup\.underline/.test(token.type)) {
|
2013-10-04 00:34:58 +00:00
|
|
|
token.value.replace(wordRegExp, function(word, offset) {
|
2013-10-05 01:30:54 +00:00
|
|
|
words.push({
|
|
|
|
value: word,
|
|
|
|
offset: offset + tokenOffset
|
|
|
|
});
|
2013-10-04 00:34:58 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
tokenOffset += token.value.length;
|
2013-10-05 01:30:54 +00:00
|
|
|
if (words.length === 0) {
|
|
|
|
self.checkToken();
|
2013-10-04 00:34:58 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-10-05 01:30:54 +00:00
|
|
|
worker.onmessage = function(e) {
|
|
|
|
var message = JSON.parse(e.data);
|
2013-10-09 01:16:49 +00:00
|
|
|
if (message[0] != 'check') {
|
2013-10-05 01:30:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
var checkedWords = message[1];
|
|
|
|
if (self.stopped) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var Range = require('ace/range').Range;
|
|
|
|
_.each(checkedWords, function(word) {
|
|
|
|
if (!word.check) {
|
|
|
|
var range = new Range(rowIndex, word.offset, rowIndex, word.offset + word.value.length);
|
|
|
|
var markerId = aceEditor.session.addMarker(range, "misspelled", "typo", true);
|
|
|
|
var marker = aceEditor.session.getMarkers(true)[markerId];
|
|
|
|
markers.push(marker);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
self.checkToken();
|
|
|
|
};
|
|
|
|
worker.postMessage(JSON.stringify(['check', words]));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
var rowIndex = 0;
|
|
|
|
|
|
|
|
function check() {
|
|
|
|
timeoutId = undefined;
|
|
|
|
currentRowCheck && (currentRowCheck.stopped = true);
|
|
|
|
currentRowCheck = new rowCheck(rowIndex++);
|
|
|
|
currentRowCheck.checkToken();
|
2013-10-04 00:34:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function stop() {
|
2013-10-05 01:30:54 +00:00
|
|
|
currentRowCheck && (currentRowCheck.stopped = true);
|
2013-10-04 00:34:58 +00:00
|
|
|
timeoutId && clearTimeout(timeoutId);
|
|
|
|
timeoutId = undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
function start() {
|
2013-10-09 01:16:49 +00:00
|
|
|
if(isInited === false || aceEditor === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
2013-10-04 00:34:58 +00:00
|
|
|
var savedMarkers = [];
|
|
|
|
_.each(markers, function(marker) {
|
|
|
|
if (marker.range.start.row < rowIndex) {
|
|
|
|
savedMarkers.push(marker);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aceEditor.session.removeMarker(marker.id);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
markers = savedMarkers;
|
|
|
|
timeoutId = setTimeout(check, 700);
|
|
|
|
}
|
2013-10-09 01:16:49 +00:00
|
|
|
|
2013-10-05 01:30:54 +00:00
|
|
|
var dropdownElt = undefined;
|
|
|
|
var $dropdownElt = undefined;
|
|
|
|
var liEltTmpl = [
|
|
|
|
'<li>',
|
|
|
|
' <a href="#">',
|
|
|
|
' <%= suggestion %>',
|
|
|
|
' </a>',
|
|
|
|
'</li>'
|
|
|
|
].join('');
|
|
|
|
|
|
|
|
var currentWordSuggest = undefined;
|
2013-10-09 01:16:49 +00:00
|
|
|
|
2013-10-05 01:30:54 +00:00
|
|
|
function wordSuggest(marker) {
|
|
|
|
var word = aceEditor.session.getTextRange(marker.range);
|
|
|
|
var self = this;
|
|
|
|
self.run = function() {
|
|
|
|
worker.onmessage = function(e) {
|
|
|
|
var message = JSON.parse(e.data);
|
2013-10-09 01:16:49 +00:00
|
|
|
if (message[0] != 'suggest') {
|
2013-10-05 01:30:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
var suggestions = message[1];
|
|
|
|
if (self.stopped) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log(suggestions);
|
|
|
|
var liListHtml = _.reduce(suggestions, function(result, suggestion) {
|
|
|
|
return result + _.template(liEltTmpl, {
|
|
|
|
suggestion: suggestion,
|
|
|
|
});
|
|
|
|
}, '');
|
|
|
|
dropdownElt.innerHTML = liListHtml;
|
|
|
|
$(dropdownElt).dropdown('toggle');
|
|
|
|
};
|
|
|
|
worker.postMessage(JSON.stringify(['suggest', word]));
|
|
|
|
};
|
|
|
|
}
|
2013-10-04 00:34:58 +00:00
|
|
|
|
|
|
|
var fileOpen = false;
|
|
|
|
spellCheck.onFileClose = function() {
|
|
|
|
stop();
|
|
|
|
fileOpen = false;
|
2013-10-03 01:02:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
spellCheck.onFileOpen = function() {
|
2013-10-04 00:34:58 +00:00
|
|
|
fileOpen = true;
|
|
|
|
rowIndex = 0;
|
|
|
|
stop();
|
|
|
|
start();
|
|
|
|
};
|
|
|
|
|
|
|
|
spellCheck.onAceCreated = function(aceEditorParam) {
|
|
|
|
aceEditor = aceEditorParam;
|
|
|
|
aceEditor.session.on('change', function(e) {
|
|
|
|
if (fileOpen === true) {
|
|
|
|
var modifiedRowIndex = e.data.range.start.row;
|
|
|
|
if (modifiedRowIndex < rowIndex) {
|
|
|
|
rowIndex = modifiedRowIndex;
|
|
|
|
}
|
|
|
|
stop();
|
|
|
|
start();
|
|
|
|
}
|
|
|
|
});
|
2013-10-05 01:30:54 +00:00
|
|
|
|
|
|
|
// Suggestions are disabled. Too much CPU consumption.
|
2013-10-04 00:34:58 +00:00
|
|
|
/*
|
|
|
|
aceEditor.on("click", function(ev) {
|
|
|
|
var screenCoordinates = aceEditor.renderer.pixelToScreenCoordinates(ev.x, ev.y);
|
|
|
|
var documentPosition = aceEditor.session.screenToDocumentPosition(screenCoordinates.row, screenCoordinates.column);
|
|
|
|
_.each(markers, function(marker) {
|
|
|
|
if (marker.range.contains(documentPosition.row, documentPosition.column)) {
|
2013-10-05 01:30:54 +00:00
|
|
|
currentWordSuggest && (currentWordSuggest.stopped = true);
|
|
|
|
currentWordSuggest = new wordSuggest(marker);
|
|
|
|
currentWordSuggest.run();
|
2013-10-03 01:02:52 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2013-10-04 00:34:58 +00:00
|
|
|
spellCheck.onReady = function() {
|
|
|
|
dropdownElt = crel('ul', {
|
|
|
|
class: 'dropdown-menu dropdown-spell-checker'
|
|
|
|
});
|
|
|
|
document.querySelector('.ui-layout-resizer-north').appendChild(crel('div', crel('div', {
|
|
|
|
'data-toggle': 'dropdown'
|
|
|
|
}), dropdownElt));
|
|
|
|
$dropdownElt = $(dropdownElt).dropdown();
|
|
|
|
*/
|
|
|
|
};
|
|
|
|
|
2013-10-03 01:02:52 +00:00
|
|
|
return spellCheck;
|
|
|
|
});
|