| Log note : there indicates place, their indicates ownership |
changed: - Introduction For those people that would like to have a spell checker in their tracker, well here is one using **aspell**. The spell checker is only executed for the web interface and not for the mail gateway. I guess it's safe to assume that e-mail clients can do the spell check for us, so there's no need to check the spelling on issues received from the mail gateway. The spell checker will check all words with exception of upper case words. Those will be skipped. In some cases we want to skip the spell check for all words. Therefor a check box can be checked. If checked, the spell check is skipped and all text is accepted as it is.<br> If a spell check is performed and spelling mistakes are found, the form will be returned with an enumeration of all misspelled words. If available, then suggestions will be given for those words to.<br> To make it easier to lookup those misspelled words, they will be marked with stars like *word*. Just go trough the text, correct the marked words (or write them in uppercase to skip them) and submit the issue again. And if you don't want the words to be skipped in uppercase, then just correct the words which need to be corrected, check the 'No spell checking' check box and re-submit the form. Requirements To use this feature, the next software if required on your server: <ul> <li> aspell (http://aspell.sourceforge.net) <li> aspell-python (http://www.republika.pl/wmula/proj/aspell-python/index.html) </ul> Implementation The spell checker is implemented in two action handlers and not in auditors. This ensures us that the spell checker will only execute for the web interface and not for the mail gateway.<br> The new action handlers only do the spell checker part. The rest of the handling is still done by the original roundup action handlers. This will keep our new action handlers plain and simple. Both action handlers are almost the same. The difference is that one is for new issues while the other one is for updating an issue.<br> To use the action handlers, only minor changes are required. Regretfully the classic 'issue.item.html' template uses a roundup method to put the *submit* button on the form together with the required hidden input fields that will tell roundup what to do, so we need to make some small changes to call the spell checker action handler in 'issue.item.html'. Even so do we need to tell the action handler which form fields to check. This is done by adding an hidden input tag to the template. This hidden tag looks like:<br> <code><input type="hidden" name="@aspell" value="<name>:<field>,..."></code><br> For the default classic template it will be:<br> <code><input type="hidden" name="@aspell" value="title:title,@note:message"></code><br> The above line will perform spell checking on HTML form fields *title* and *@note*. If errors are found in these fields, the error message will refer to the fields *title* and *message* (like they are named on the page). Best regards,<br> Marlon van den Berg <hr> Source Code These are the two new action handlers. Copy the content to a file and save it in folder '<tracker_home>/extensions':: class AspellClass: def check(self): """\ Check if a form input field has some spelling mistakes. If it has, it returns a tuple with a dictionary on the first tuple index and the marked up text on the second tuple index. The keys of the dictionary contain all the spelling mistakes. The items contain a tuple with suggestions for the word. The marked up text is the original input form field with '*' around the spelling mistakes. """ def __inner(text): """\ Does all the work. """ import aspell import re # select english language sp = aspell.Speller('lang', 'en') # split the text into list of words # (excluding punctuation marks) word_list = re.split('\W+', text) new_text = text errors = {} for word in word_list: # skip empty words (not words at all) and # skip upercase words if word and not word.isupper(): word = word.lower() # if it isn't checked before if not errors.has_key(word): # perform spellcheck on word if not sp.check(word): # word incorrect suggestions = sp.suggest(word) if suggestions: # put spelling mistake in error list with suggestions errors[word] = suggestions # put some markings around the word res = re.compile('\\b(%s)\\b'%word, re.IGNORECASE) new_text = res.sub('*\\1*', new_text) return (errors, new_text) if self.form.has_key('no_spell_check') \ and self.form['no_spell_check'].value == '1': # no spell check requested return None errors = [] if self.form.has_key('@aspell'): _aspell = '@aspell' elif self.form.has_key(':aspell'): _aspell = ':aspell' else: _aspell = None if _aspell: for field in self.form[_aspell].value.split(','): form_name, nice_name = field.split(':') if self.form.has_key(form_name): new_errors, text = __inner(self.form[form_name].value) if new_errors: # update form text (will place the markings around # the spelling mistakes) self.form[form_name].value = text if errors: # more than one form field has a spelling mistake errors.append('<br>') # tell the user which form field has the spelling mistake errors.append("<i>%s</i> contains spelling error(s):"%nice_name) # add each spelling mistake to the error message for word, suggest in new_errors.items(): errors.append('''<br>\ <b style="color:yellow">%s</b> - <select><option>%s</option></select>'''% \ (word, '</option><option>'.join(suggest))) self.form.value.remove(self.form[_aspell]) return errors class Aspell_NewItemAction(AspellClass, NewItemAction): def handle(self): # perform spell check errors = self.check() if errors: # we have some spelling mistakes self.client.error_message.extend(errors) return else: # let RoundUp do the rest NewItemAction.handle(self) class Aspell_EditItemAction(AspellClass, actions.EditItemAction): def handle(self): # perform spell check errors = self.check() if errors: # we have some spelling mistakes self.client.error_message.extend(errors) return else: # let RoundUp do the rest actions.EditItemAction.handle(self) def init(instance): instance.registerAction('aspell_new_item', Aspell_NewItemAction) instance.registerAction('aspell_edit_item', Aspell_EditItemAction) Here are the changes for the 'issue.item.html' template.<br> Lookup this part:: <td colspan=3> <span tal:replace="structure context/submit">submit button</span> <a tal:condition="context/id" tal:attributes="href context/copy_url" i18n:translate="">Make a copy</a> </td> and replace it with:: <td colspan=3> <tal:block tal:condition="not:context/id"> <input type="hidden" name="@action" value="aspell_new"> <input type="submit" name="submit" value="Submit New Entry"> </tal:block> <tal:block tal:condition="context/id"> <input type="hidden" name="@lastactivity" tal:attributes="value context/activity"> <input type="hidden" name="@action" value="aspell_edit"> <input type="submit" name="submit" value="Submit Changes"> <a tal:attributes="href context/copy_url" i18n:translate="">Make a copy</a> </tal:block> <input type="hidden" name="@aspell" value="title:title,@note:message"> <input type="checkbox" name="no_spell_check" value="1">No spell checking </td>