diff --git a/res/extensions/spellCheck.js b/res/extensions/spellCheck.js index e5d95ae3..d92ebc63 100644 --- a/res/extensions/spellCheck.js +++ b/res/extensions/spellCheck.js @@ -1,6 +1,7 @@ define([ "jquery", "underscore", + "crel", "utils", "classes/Extension", "typo-js", @@ -8,43 +9,139 @@ define([ "text!dictionaries/en_US.dic", "text!dictionaries/en_US.aff", "text!html/tocSettingsBlock.html", - ], function($, _, utils, Extension, Typo, XRegExp, dic, aff, tocSettingsBlockHTML) { + ], function($, _, crel, utils, Extension, Typo, XRegExp, dic, aff, tocSettingsBlockHTML) { var spellCheck = new Extension("spellCheck", "Spell Check", true); spellCheck.settingsBlock = tocSettingsBlockHTML; var aceEditor = undefined; + var timeoutId = undefined; + var dictionary = new Typo('en_US', aff, dic); + var wordRegExp = XRegExp('\\p{L}+', 'g'); + var markers = []; + var rowIndex = 0; + + function check() { + var tokenOffset = 0, + processedTokens = 0; + var Range = require('ace/range').Range; + + function checkToken(token) { + if (token.checked === undefined && !/code|code_block|reference|markup\.underline/.test(token.type)) { + token.value.replace(wordRegExp, function(word, offset) { + if (!dictionary.check(word)) { + offset += tokenOffset; + var range = new Range(rowIndex, offset, rowIndex, offset + word.length); + var markerId = aceEditor.session.addMarker(range, "misspelled", "typo", true); + var marker = aceEditor.session.getMarkers(true)[markerId]; + console.log(marker); + markers.push(marker); + } + }); + processedTokens++; + } + token.checked = true; + tokenOffset += token.value.length; + } + var rowCount = aceEditor.session.getDocument().getLength(); + for (; rowIndex < rowCount; rowIndex++) { + var tokens = aceEditor.session.getTokens(rowIndex); + tokenOffset = 0; + _.each(tokens, checkToken); + if (processedTokens > 5) { + timeoutId = setTimeout(check, 20); + return; + } + } + } + + function stop() { + timeoutId && clearTimeout(timeoutId); + timeoutId = undefined; + } + + function start() { + var savedMarkers = []; + console.log(rowIndex); + _.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); + } + + var fileOpen = false; + spellCheck.onFileClose = function() { + stop(); + fileOpen = false; + }; + + spellCheck.onFileOpen = function() { + fileOpen = true; + rowIndex = 0; + stop(); + start(); + }; + +/* + var dropdownElt = undefined; + var $dropdownElt = undefined; + var liEltTmpl = [ + '
  • ', + ' ', + ' <%= suggestion %>', + ' ', + '
  • ' + ].join(''); + */ spellCheck.onAceCreated = function(aceEditorParam) { aceEditor = aceEditorParam; - }; - - var context = undefined; - spellCheck.onFileClose = function() { - if (context !== undefined) { - _.each(context.markers, function(marker) { - aceEditor.session.removeMarker(marker); - }); - } - context = undefined; - }; - - var dictionary = new Typo('en_US', aff, dic); - spellCheck.onFileOpen = function() { - context = { - markers: [] - }; - var Range = require('ace/range').Range; - var lines = aceEditor.session.getDocument().getAllLines(); - _.each(lines, function(line, index) { - line.replace(XRegExp('\\p{L}+', 'g'), function(word, offset) { - if (!dictionary.check(word)) { - console.log(word); - var range = new Range(index, offset, index, offset + word.length); - context.markers[index] = aceEditor.session.addMarker(range, "misspelled", "typo", true); + aceEditor.session.on('change', function(e) { + if (fileOpen === true) { + var modifiedRowIndex = e.data.range.start.row; + if (modifiedRowIndex < rowIndex) { + rowIndex = modifiedRowIndex; + } + stop(); + start(); + } + }); + /* + 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)) { + var word = aceEditor.session.getTextRange(marker.range); + var suggestions = dictionary.suggest(word.toLowerCase()); + console.log(word, suggestions); + var liListHtml = _.reduce(suggestions, function(result, suggestion) { + return result + _.template(liEltTmpl, { + suggestion: suggestion, + }); + }, ''); + dropdownElt.innerHTML = liListHtml; + $(dropdownElt).dropdown('toggle'); } }); }); }; + 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(); + */ + }; + return spellCheck; }); \ No newline at end of file diff --git a/res/styles/main.less b/res/styles/main.less index df6f971a..efc7e74b 100644 --- a/res/styles/main.less +++ b/res/styles/main.less @@ -1025,7 +1025,12 @@ ul,ol { color: @primary-color-lighter; } - .ace_marker-layer .misspelled { position: absolute; z-index: -2; border-bottom: 1px dotted red; margin-bottom: -1px; } + .ace_marker-layer .misspelled { + position: absolute; + z-index: -2; + border-bottom: 1px dotted red; + margin-bottom: -1px; + } } .ace_search {