Skip to content
Snippets Groups Projects
Commit d4d066fc authored by robinwilliam.hundt's avatar robinwilliam.hundt
Browse files

Added rendering of asciimath in submissions

parent a6e1dfaf
No related branches found
Tags 5.0.0
1 merge request!206Added rendering of asciimath in submissions
Pipeline #115775 failed
This commit is part of merge request !206. Comments created here will be created in the context of that merge request.
...@@ -37,6 +37,7 @@ class SubmissionType(models.Model): ...@@ -37,6 +37,7 @@ class SubmissionType(models.Model):
HASKELL = 'haskell' HASKELL = 'haskell'
TEXT = 'plaintext' TEXT = 'plaintext'
PYTHON = 'python' PYTHON = 'python'
MARKDOWN = 'markdown'
LANGUAGE_CHOICES = ( LANGUAGE_CHOICES = (
(C, 'C syntax highlighting'), (C, 'C syntax highlighting'),
...@@ -44,6 +45,7 @@ class SubmissionType(models.Model): ...@@ -44,6 +45,7 @@ class SubmissionType(models.Model):
(MIPS, 'Mips syntax highlighting'), (MIPS, 'Mips syntax highlighting'),
(HASKELL, 'Haskell syntax highlighting'), (HASKELL, 'Haskell syntax highlighting'),
(PYTHON, 'Python syntax highlighting'), (PYTHON, 'Python syntax highlighting'),
(MARKDOWN, 'Markdown syntax highlighting with asciimath rendering'),
(TEXT, 'No syntax highlighting'), (TEXT, 'No syntax highlighting'),
) )
......
...@@ -35,20 +35,20 @@ ...@@ -35,20 +35,20 @@
"@types/mocha": "^5.2.5", "@types/mocha": "^5.2.5",
"@types/nightwatch": "^0.9.8", "@types/nightwatch": "^0.9.8",
"@types/sinon": "^7.0.2", "@types/sinon": "^7.0.2",
"@typescript-eslint/eslint-plugin": "^2.3.2",
"@typescript-eslint/parser": "^2.3.2",
"@vue/cli-plugin-eslint": "^3.11.0", "@vue/cli-plugin-eslint": "^3.11.0",
"@vue/cli-plugin-typescript": "^3.11.0", "@vue/cli-plugin-typescript": "^3.11.0",
"@vue/cli-plugin-unit-mocha": "^3.11.0", "@vue/cli-plugin-unit-mocha": "^3.11.0",
"@vue/cli-service": "^3.11.0", "@vue/cli-service": "^3.11.0",
"@vue/test-utils": "^1.0.0-beta.29",
"@vue/eslint-config-typescript": "^4.0.0", "@vue/eslint-config-typescript": "^4.0.0",
"@typescript-eslint/parser": "^2.3.2", "@vue/test-utils": "^1.0.0-beta.29",
"@typescript-eslint/eslint-plugin": "^2.3.2",
"chai": "^4.2.0", "chai": "^4.2.0",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"mocha": "^5.2.0", "mocha": "^5.2.0",
"mock-local-storage": "^1.1.8", "mock-local-storage": "^1.1.8",
"sinon": "^7.2.2", "sinon": "^7.2.2",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"typescript": "^3.4.3", "typescript": "^3.4.3",
"vue-template-compiler": "^2.5.16", "vue-template-compiler": "^2.5.16",
"webpack": "^4.41.0" "webpack": "^4.41.0"
......
...@@ -6,11 +6,14 @@ ...@@ -6,11 +6,14 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Grady</title> <title>Grady</title>
<script id="MathJax-script" async src="https://grady.informatik.uni-goettingen.de/static/mathjax/es5/tex-mml-chtml.js"></script>
<script> <script>
MathJax = { MathJax = {
loader: {load: ['input/asciimath', 'output/chtml', 'input/tex']},
asciimath: {
delimiters: [['$', '$']]
},
options: { options: {
skipHtmlTags: [ // HTML tags that won't be searched for math skipHtmlTags: [// HTML tags that won't be searched for math
'script', 'noscript', 'style', 'textarea', 'pre', 'script', 'noscript', 'style', 'textarea', 'pre',
'code', 'annotation', 'annotation-xml' 'code', 'annotation', 'annotation-xml'
], ],
...@@ -22,6 +25,7 @@ ...@@ -22,6 +25,7 @@
} }
}; };
</script> </script>
<script id="MathJax-script" async src="https://grady.informatik.uni-goettingen.de/static/mathjax/es5/startup.js"></script>
</head> </head>
<body class="tex2jax_ignore"> <body class="tex2jax_ignore">
<noscript> <noscript>
......
...@@ -79,7 +79,7 @@ import FeedbackLabel from '@/components/feedback_labels/FeedbackLabel.vue' ...@@ -79,7 +79,7 @@ import FeedbackLabel from '@/components/feedback_labels/FeedbackLabel.vue'
import { FeedbackLabels as Labels } from '@/store/modules/feedback-labels' import { FeedbackLabels as Labels } from '@/store/modules/feedback-labels'
import LabelSelector from '@/components/feedback_labels/LabelSelector.vue' import LabelSelector from '@/components/feedback_labels/LabelSelector.vue'
import SubmissionLine from '@/components/submission_notes/base/SubmissionLine' import SubmissionLine from '@/components/submission_notes/base/SubmissionLine'
import { SubmissionNotes } from '@/store/modules/submission-notes' import { SubmissionNotes, subNotesEventBus } from '@/store/modules/submission-notes'
import { Authentication } from '@/store/modules/authentication' import { Authentication } from '@/store/modules/authentication'
import { actions } from '@/store/actions' import { actions } from '@/store/actions'
import { fetchFeedback } from '@/api' import { fetchFeedback } from '@/api'
...@@ -148,6 +148,11 @@ export default { ...@@ -148,6 +148,11 @@ export default {
}, },
submissionWithoutAssignment: function () { submissionWithoutAssignment: function () {
this.init() this.init()
},
submission: function (oldVal, newVal) {
if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
subNotesEventBus.$emit('submissionChanged')
}
} }
}, },
created () { created () {
......
<template> <template>
<div> <div>
<slot name="header" /> <slot name="header" />
<table class="submission-table elevation-1"> <table
id="submission-table"
class="latex submission-table elevation-1"
>
<slot name="table-content" /> <slot name="table-content" />
</table> </table>
<slot name="labels" /> <slot name="labels" />
......
...@@ -16,13 +16,14 @@ ...@@ -16,13 +16,14 @@
</td> </td>
<td class="code-cell-content pl-2"> <td class="code-cell-content pl-2">
<!-- eslint-disable-next-line --> <!-- eslint-disable-next-line -->
<span class="code-line" v-html="code"/> <span class="code-line" :key="key" v-html="code"/>
<slot /> <slot />
</td> </td>
</div> </div>
</template> </template>
<script> <script>
import { subNotesEventBus } from '../../../store/modules/submission-notes'
export default { export default {
name: 'SubmissionLine', name: 'SubmissionLine',
props: { props: {
...@@ -43,11 +44,21 @@ export default { ...@@ -43,11 +44,21 @@ export default {
default: false, default: false,
}, },
}, },
data () {
return {
key: 0
}
},
computed: { computed: {
backgroundColor() { backgroundColor() {
return this.hint ? 'background-color: #F44336;' : 'background-color: transparent;' return this.hint ? 'background-color: #F44336;' : 'background-color: transparent;'
} }
}, },
created () {
subNotesEventBus.$on('resetSubmission', () => {
this.key++
})
},
methods: { methods: {
toggleEditor () { toggleEditor () {
this.$emit('toggleEditor') this.$emit('toggleEditor')
......
...@@ -14,6 +14,20 @@ ...@@ -14,6 +14,20 @@
</v-dialog> </v-dialog>
<span class="title">Submission of {{ ofStudent }}</span> <span class="title">Submission of {{ ofStudent }}</span>
<toggle-feedback-visibility-button /> <toggle-feedback-visibility-button />
<div v-if="isMarkdown">
<v-btn
v-if="!mathIsRendered"
@click="renderAsciiMath"
>
Render Math
</v-btn>
<v-btn
v-else
@click="resetSubmission"
>
Reset Math
</v-btn>
</div>
<v-spacer /> <v-spacer />
<v-tooltip <v-tooltip
v-if="sourceCodeAvailable" v-if="sourceCodeAvailable"
...@@ -45,9 +59,12 @@ ...@@ -45,9 +59,12 @@
import CorrectionHelpCard from '@/components/submission_notes/CorrectionHelpCard' import CorrectionHelpCard from '@/components/submission_notes/CorrectionHelpCard'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import ToggleFeedbackVisibilityButton from '@/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton' import ToggleFeedbackVisibilityButton from '@/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton'
import { SubmissionNotes } from '@/store/modules/submission-notes' import { SubmissionNotes, subNotesEventBus } from '@/store/modules/submission-notes'
import {fetchSubmissionSourceCode} from '@/api.ts' import {fetchSubmissionSourceCode} from '@/api.ts'
import {saveAs} from 'file-saver' import {saveAs} from 'file-saver'
import store from '../../../store/store'
import { SubmissionType } from '../../../models'
import Vue from 'vue'
export default { export default {
name: 'AnnotatedSubmissionTopToolbar', name: 'AnnotatedSubmissionTopToolbar',
...@@ -63,15 +80,44 @@ export default { ...@@ -63,15 +80,44 @@ export default {
data () { data () {
return { return {
helpDialog: false, helpDialog: false,
copyMessage: 'Copy to clipboard' copyMessage: 'Copy to clipboard',
mathIsRendered: false
} }
}, },
computed: { computed: {
sourceCodeAvailable () { sourceCodeAvailable () {
return SubmissionNotes.state.submission.sourceCodeAvailable return SubmissionNotes.state.submission.sourceCodeAvailable
},
isMarkdown () {
const typePk = SubmissionNotes.state.submission.type
const type = store.state.submissionTypes[typePk]
return type.programmingLanguage === SubmissionType.ProgrammingLanguageEnum.Markdown
}
},
created () {
subNotesEventBus.$on('submissionChanged', () => {
if (this.mathIsRendered) {
this.$nextTick(() => {
this.renderAsciiMath()
})
}
})
},
mounted () {
const lang = SubmissionNotes.submissionType.programmingLanguage
if (lang === SubmissionType.ProgrammingLanguageEnum.Markdown) {
this.renderAsciiMath()
} }
}, },
methods: { methods: {
renderAsciiMath () {
window.MathJax.typeset()
this.mathIsRendered = true
},
resetSubmission () {
this.mathIsRendered = false
subNotesEventBus.$emit('resetSubmission')
},
async downloadSourceCode () { async downloadSourceCode () {
const data = await fetchSubmissionSourceCode(SubmissionNotes.state.submission.pk) const data = await fetchSubmissionSourceCode(SubmissionNotes.state.submission.pk)
saveAs(new Blob([data.sourceCode], {type: 'application/json'}), 'notebook.ipynb') saveAs(new Blob([data.sourceCode], {type: 'application/json'}), 'notebook.ipynb')
......
...@@ -137,10 +137,13 @@ export default class SubmissionType extends Vue { ...@@ -137,10 +137,13 @@ export default class SubmissionType extends Vue {
} }
@Watch('description') @Watch('description')
onDescriptionChanged(val: string) { onDescriptionChanged(newVal: string, oldVal: string) {
this.$nextTick().then(() => { console.log(`desc rerender old ${oldVal} new ${newVal}`)
window.MathJax.typeset() if (oldVal !== newVal) {
}) this.$nextTick().then(() => {
window.MathJax.typeset()
})
}
} }
mounted () { mounted () {
......
...@@ -640,8 +640,9 @@ export namespace SubmissionType { ...@@ -640,8 +640,9 @@ export namespace SubmissionType {
* @enum {string} * @enum {string}
*/ */
export enum ProgrammingLanguageEnum { export enum ProgrammingLanguageEnum {
C = 'c' as any, C = 'c',
Java = 'java' as any Java = 'java',
Markdown = 'markdown'
} }
} }
......
import Vue from 'vue' import Vue from 'vue'
import * as hljs from 'highlight.js' import * as hljs from 'highlight.js'
import * as api from '@/api' import * as api from '@/api'
import { Feedback, FeedbackComment, SubmissionNoType, CreateUpdateFeedback } from '@/models' import { Feedback, FeedbackComment, SubmissionNoType, CreateUpdateFeedback, SubmissionType } from '@/models'
import { RootState } from '@/store/store' import { RootState } from '@/store/store'
import { getStoreBuilder, BareActionContext } from 'vuex-typex' import { getStoreBuilder, BareActionContext } from 'vuex-typex'
import { syntaxPostProcess } from '@/util/helpers' import { syntaxPostProcess } from '@/util/helpers'
import { AxiosResponse } from 'axios' import { AxiosResponse } from 'axios'
import { Assignments } from './assignments' import { Assignments } from './assignments'
export const subNotesEventBus = new Vue()
export interface SubmissionNotesState { export interface SubmissionNotesState {
submission: SubmissionNoType submission: SubmissionNoType
ui: { ui: {
...@@ -70,7 +72,11 @@ const submissionGetter = mb.read(function submission(state, getters) { ...@@ -70,7 +72,11 @@ const submissionGetter = mb.read(function submission(state, getters) {
const language = getters.submissionType const language = getters.submissionType
? getters.submissionType.programmingLanguage ? getters.submissionType.programmingLanguage
: 'c' : 'c'
const highlighted = hljs.highlight(language, state.submission.text || '', true).value let highlighted = state.submission.text || ''
if (language !== SubmissionType.ProgrammingLanguageEnum.Markdown) {
highlighted = hljs.highlight(language, highlighted, true).value
}
// const highlighted = state.submission.text || ''
const postProcessed = syntaxPostProcess(highlighted) const postProcessed = syntaxPostProcess(highlighted)
const splitted = postProcessed.split('\n').reduce((acc: { [k: number]: string }, cur, index) => { const splitted = postProcessed.split('\n').reduce((acc: { [k: number]: string }, cur, index) => {
acc[index + 1] = cur acc[index + 1] = cur
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment