Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
johanneswilm committed Sep 13, 2017
0 parents commit f22a017
Show file tree
Hide file tree
Showing 13 changed files with 1,145 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.pyc
*~
dist/
fiduswriter_languagetool.egg-info/
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include LICENSE
include README.rst
recursive-include languagetool/static *
recursive-include languagetool/locale *
34 changes: 34 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
=====
FidusWriter-Languagetool
=====

FidusWriter-Languagetool is a Fidus writer plugin to connect a Fidus Writer instance
with Languagetool (LT).


Installation
-----------

1. Install Fidus Writer if you haven't done so already.

2. Within the virtual environment set up for your Fidus Writer instance, install the version of the plugin corresponding to your Fidus Writer installation. If you are running Fidus Writer 3.2, the command is::

pip install "fiduswriter-languagetool<3.3"

3. Add "languagetool" to your INSTALLED_APPS setting in the configuration.py file
like this::

INSTALLED_APPS += (
...
'languagetool',
)

4. Add a setting for the URL where you will be running LT in the configuration.py file like this:

LT_URL = 'http://localhost:8081'

5. Create the needed JavaScript files by running this::

python manage.py transpile

6. (Re)start your Fidus Writer server.
Empty file added languagetool/__init__.py
Empty file.
38 changes: 38 additions & 0 deletions languagetool/locale/en_US/LC_MESSAGES/djangojs.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-14 00:58+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: static/js/es6_modules/lt/dialog.js:13
msgid "Cancel"
msgstr ""

#: static/js/es6_modules/lt/editor.js:15
msgid "Finish language check"
msgstr ""

#: static/js/es6_modules/lt/editor.js:16
msgid "Remove lines left over in the text from language check."
msgstr ""

#: static/js/es6_modules/lt/editor.js:28
msgid "Check language"
msgstr ""

#: static/js/es6_modules/lt/editor.js:29
msgid "Check text for grammar and spelling issues."
msgstr ""
36 changes: 36 additions & 0 deletions languagetool/proxy_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from future.moves.urllib.parse import urljoin

from tornado.web import RequestHandler, asynchronous, HTTPError
from tornado.httpclient import AsyncHTTPClient
from base.django_handler_mixin import DjangoHandlerMixin
from django.conf import settings

LT_URL = settings.LT_URL \
if settings.LT_URL else 'https://languagetool.org/api/'


class Proxy(DjangoHandlerMixin, RequestHandler):
@asynchronous
def post(self, relative_url):
user = self.get_current_user()
if not user.is_authenticated():
self.set_status(401)
self.finish()
return
body = self.request.body
url = urljoin(LT_URL, '/v2/') + relative_url
http = AsyncHTTPClient()
http.fetch(
url,
method='POST',
body=body,
callback=self.on_response
)

# The response is asynchronous so that the getting of the data from the
# remote server doesn't block the server connection.
def on_response(self, response):
if response.error:
raise HTTPError(500)
self.write(response.body)
self.finish()
61 changes: 61 additions & 0 deletions languagetool/static/js/es6_modules/lt/dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {dialogTemplate} from "./templates"
import {removeDecorationsBetween} from "./statePlugin"

export class DialogLT {
constructor(editor, view, match) {
this.editor = editor
this.view = view
this.match = match
}

init() {
let buttons = [{
text: gettext('Cancel'),
click: () => {
this.dialog.dialog('close')
},
class: 'fw-button fw-orange'
}]
let dialogDOM = dialogTemplate({
header: this.match.shortMessage,
message: this.match.message,
replacements: this.match.replacements
})
this.dialog = jQuery(dialogDOM)
this.dialog.dialog({
width: 320,
height: 540,
buttons,
create: () => this.dialogCreate(),
close: () => {
this.dialog.dialog('destroy').remove()
}
})
}

dialogCreate() {
let that = this
jQuery(this.dialog).on('click', '.replacement', function() {
let id = parseInt(jQuery(this).data('id'))

let replacement = that.match.replacements[id]
if (replacement) {
let removeDecosTr = removeDecorationsBetween(
that.view.state,
that.view.state.selection.from,
that.view.state.selection.to
)
that.view.dispatch(removeDecosTr)

let transaction = that.view.state.tr.replaceSelectionWith(
that.view.state.schema.text(replacement.value),
true
)
that.view.dispatch(transaction)
}
console.log(replacement)
that.dialog.dialog('close')
that.view.focus()
})
}
}
128 changes: 128 additions & 0 deletions languagetool/static/js/es6_modules/lt/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import {languagetoolPlugin, setDecorations, removeDecorations} from "./statePlugin"

export class EditorLT {
constructor(editor) {
this.editor = editor
this.supportedLanguages = []
this.hasChecked = false
}

init() {
let toolMenu = this.editor.menu.headerbarModel.content.find(menu => menu.id==='tools')

toolMenu.content.unshift(
{
title: gettext('Finish language check'),
tooltip: gettext('Remove lines left over in the text from language check.'),
action: editor => {
this.removeMainDecos()
this.removeFnDecos()
this.hasChecked = false
},
disabled: editor => !this.hasChecked
}
)

toolMenu.content.unshift(
{
title: gettext('Check language'),
tooltip: gettext('Check text for grammar and spelling issues.'),
action: editor => {
let language = this.editor.view.state.doc.firstChild.attrs.language
this.proofread(this.editor.view, language)
this.proofread(this.editor.mod.footnotes.fnEditor.view, language)
},
disabled: editor => !this.supportedLanguages.includes(
editor.view.state.doc.firstChild.attrs.language
) || this.editor.docInfo.access_rights !== 'write'
}
)
this.editor.statePlugins.push(
[languagetoolPlugin, () => ({editor: this.editor, editorLt: this})]
)
this.editor.mod.footnotes.fnEditor.fnStatePlugins.push(
[languagetoolPlugin, () => ({editor: this.editor, editorLt: this})]
)


this.getSupportedLanguages()
}

getSupportedLanguages() {
fetch('/proxy/languagetool/languages', {
method: "POST",
credentials: "same-origin",
}).then(response => response.json()).then(json => {
this.supportedLanguages = json.map(entry => entry.longCode)
})
}

proofread(view, language) {
let text = this.getText(view.state.doc)
let state = view.state
fetch('/proxy/languagetool/check', {
method: "POST",
credentials: "same-origin",
body: new URLSearchParams(Object.entries({
text,
language
}))
}).then(response => response.json()).then(json => {
if(view.state===state) {
// No changes have been made while spell checking took place.
this.markMatches(view, json.matches)
this.hasChecked = true
} else {
// something has changed, run spellchecker again.
this.proofread(view, language)
}
})
}

getText(node) {
let start = '', end = ''
if (node.type.name==='text') {
return node.text
} else if (node.isBlock) {
let text = ''
let childCount = node.childCount, i
for (i = 0; i < childCount; i++) {
text += this.getText(node.child(i))
}
if (node.type.name==='doc') {
return text
} else {
return `\n${text}\n`
}
} else {
return ' '.repeat(node.nodeSize)
}
}

markMatches(view, matches) {
if(!matches.length) {
return
}
let tr = setDecorations(view.state, matches)
if (tr) {
view.dispatch(tr)
}
}

removeFnDecos() {
this.removeDecos(this.editor.mod.footnotes.fnEditor.view)
}

removeMainDecos() {
this.removeDecos(this.editor.view)
}

removeDecos(view) {
let tr = removeDecorations(view.state)
if (tr) {
view.dispatch(tr)
}
this.hasChecked = false
}

}
Loading

0 comments on commit f22a017

Please sign in to comment.