asciidoctor-question 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.adoc +35 -0
- data/LICENSE.adoc +22 -0
- data/README.adoc +130 -0
- data/Rakefile +2 -0
- data/images/gap.png +0 -0
- data/images/mc.png +0 -0
- data/lib/asciidoctor-question/extensions.rb +40 -0
- data/lib/asciidoctor-question/gap/extension.rb +72 -0
- data/lib/asciidoctor-question/multiple_choice/extension.rb +106 -0
- data/lib/asciidoctor-question/question/extension.rb +70 -0
- data/lib/asciidoctor-question/question/post_processor.rb +41 -0
- data/lib/asciidoctor-question/question.rb +12 -0
- data/lib/asciidoctor-question/version.rb +5 -0
- data/lib/asciidoctor-question.rb +1 -0
- data/res/asciidoctor-question/question.css +28 -0
- data/res/asciidoctor-question/question.js +53 -0
- data/test/test.adoc +54 -0
- data/test/test.rb +5 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 01e688b1fd4efa2544898b54ec6f3fc78e855456
|
4
|
+
data.tar.gz: 697269794fcf44fbf1e8481eded01fd4ef647b28
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ffcdf42dcb9d4ab87324ae6b00abba115d76dcae6c6cf08a0c16ba978c5bb74bbaf087911bc0b10e6d9593b30ae4d287ae2e3ac62c8c41198600b94f1837ceb7
|
7
|
+
data.tar.gz: 8b60dc0d1c785cacc700f70e72badde086983c68c093a21769a0e8654c32e9a50f0c288b4235bcbb602ec2a4afb3d1b9e0294e91986021b7a59a016ff7f87f5d
|
data/CHANGELOG.adoc
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
= Asciidoctor-question Changelog
|
2
|
+
|
3
|
+
== Development
|
4
|
+
|
5
|
+
== 0.4
|
6
|
+
|
7
|
+
Enhancements::
|
8
|
+
* add attribute :solution: for PDF generation - this generates a PDF with the solutions to the questions
|
9
|
+
|
10
|
+
== 0.3
|
11
|
+
|
12
|
+
Enhancements::
|
13
|
+
|
14
|
+
* add README.adoc
|
15
|
+
* add LICENSE.adoc
|
16
|
+
* add CHANGELOG.adoc
|
17
|
+
* add reset button to every question
|
18
|
+
|
19
|
+
Bug Fixes::
|
20
|
+
|
21
|
+
* add the macro substitution to source blocks, if it is in a gap text question
|
22
|
+
* make the mc correct or incorrect icons smaller
|
23
|
+
* mc correct and incorrect icons not working in firefox
|
24
|
+
|
25
|
+
== 0.2
|
26
|
+
|
27
|
+
Enhancements::
|
28
|
+
|
29
|
+
* add support for the `question` block with gap type
|
30
|
+
|
31
|
+
== 0.1
|
32
|
+
|
33
|
+
Initial release::
|
34
|
+
|
35
|
+
* Provides Asciidoctor extension for `question` blocks with a mc type
|
data/LICENSE.adoc
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
.The MIT License (MIT)
|
2
|
+
....
|
3
|
+
Copyright (c) 2016 Marcel Hoppe and Technische Hochschule Mittelhessen - University of Applied Sciences
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
22
|
+
....
|
data/README.adoc
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
= Asciidoctor Question
|
2
|
+
Marcel Hoppe <marcel.hoppe@mni.thm.de>
|
3
|
+
:description: README for the Asciidoctor Question extension for Asciidoctor.
|
4
|
+
:version: 0.4
|
5
|
+
|
6
|
+
ifdef::env-github[:toc: macro]
|
7
|
+
ifndef::env-site[:toc: preamble]
|
8
|
+
ifndef::imagesdir[:imagesdir: images]
|
9
|
+
:icons: font
|
10
|
+
:source-highlighter: coderay
|
11
|
+
:source-language: asciidoc
|
12
|
+
:table-caption!:
|
13
|
+
:example-caption!:
|
14
|
+
:figure-caption!:
|
15
|
+
:check: icon:check[]
|
16
|
+
ifdef::env-github[:check: :ballot_box_with_check:]
|
17
|
+
ifndef::env-site[:status:]
|
18
|
+
:uri-asciidoctor-api: http://asciidoctor.org/docs/user-manual/#api
|
19
|
+
:uri-asciidoctor-extensions: http://asciidoctor.org/docs/user-manual/#extension-points
|
20
|
+
|
21
|
+
image:https://img.shields.io/gem/v/asciidoctor-question.svg?label=gem%20version[Gem Version, link=https://rubygems.org/gems/asciidoctor-question]
|
22
|
+
image:https://img.shields.io/badge/license-MIT-blue.svg[MIT License, link=#copyright]
|
23
|
+
|
24
|
+
Asciidoctor Question is a set of Asciidoctor extensions that allows you to add questions as multiple choice and gap text. The questions are defined using plain text in your AsciiDoc document.
|
25
|
+
|
26
|
+
ifeval::["{toc-placement}" == "macro"]
|
27
|
+
[discrete]
|
28
|
+
== Contents
|
29
|
+
|
30
|
+
toc::[title={blank}]
|
31
|
+
endif::[]
|
32
|
+
|
33
|
+
== Installation
|
34
|
+
|
35
|
+
There are two options to install Asciidoctor Question. First using `gem install` on the CLI:
|
36
|
+
|
37
|
+
$ gem install asciidoctor-question
|
38
|
+
|
39
|
+
or by adding the following entry to your project's [.path]_Gemfile_.
|
40
|
+
|
41
|
+
.Gemfile
|
42
|
+
[source,ruby,subs="verbatim,attributes"]
|
43
|
+
----
|
44
|
+
gem 'asciidoctor-question', '~> {version}'
|
45
|
+
----
|
46
|
+
|
47
|
+
and execute `bundle` in the CLI.
|
48
|
+
|
49
|
+
$ bundle
|
50
|
+
|
51
|
+
== Creating a Question
|
52
|
+
|
53
|
+
A question is written inside a literal block, which needs two attributes.
|
54
|
+
|
55
|
+
.Anatomy of a question
|
56
|
+
----
|
57
|
+
[question, question-type] // <1> <2>
|
58
|
+
.... // <3>
|
59
|
+
Question in appropriate syntax
|
60
|
+
....
|
61
|
+
----
|
62
|
+
<1> The first positional attribute in the attribute list specifies that this block is a question.
|
63
|
+
<2> The second positional attribute defines the type of this question (mc or gap)
|
64
|
+
<3> Place the attribute list directly on top of the delimited literal block (+....+). You can also use an example (+====+) or open block (`--`) as an alternative.
|
65
|
+
|
66
|
+
The following question types are available:
|
67
|
+
|
68
|
+
[cols="2,3a,3a",options="header"]
|
69
|
+
|===
|
70
|
+
|Question Type
|
71
|
+
|input
|
72
|
+
|output
|
73
|
+
|
74
|
+
|mc
|
75
|
+
|
|
76
|
+
[source]
|
77
|
+
----
|
78
|
+
[question, mc]
|
79
|
+
....
|
80
|
+
Lorem ipsum dolor sit amet, consetetur
|
81
|
+
sadipscing elitr, sed diam nonumy eirmod
|
82
|
+
tempor invidunt ut labore et dolore
|
83
|
+
magna aliquyam erat, sed diam voluptua.
|
84
|
+
|
85
|
+
- [X] ipsum
|
86
|
+
- [ ] eltir
|
87
|
+
- [X] ut
|
88
|
+
....
|
89
|
+
----
|
90
|
+
|
|
91
|
+
|
92
|
+
image::mc.png[]
|
93
|
+
|
94
|
+
|gap
|
95
|
+
|
|
96
|
+
[source]
|
97
|
+
----
|
98
|
+
[question, gap]
|
99
|
+
....
|
100
|
+
At vero eos et __accusam__ et justo
|
101
|
+
duo dolores et ea rebum. Stet clita
|
102
|
+
kasd gubergren, no sea __takimata
|
103
|
+
sanctus est Lorem__ ipsum dolor sit
|
104
|
+
amet. Lorem __ipsum dolor sit amet__,
|
105
|
+
consetetur sadipscing elitr, sed diam
|
106
|
+
nonumy __eirmod tempor invidunt__ ut
|
107
|
+
labore et dolore magna aliquyam erat,
|
108
|
+
sed diam voluptua.
|
109
|
+
....
|
110
|
+
----
|
111
|
+
|
|
112
|
+
image::gap.png[]
|
113
|
+
|===
|
114
|
+
|
115
|
+
|
116
|
+
== Generating a Question Document from a Terminal
|
117
|
+
|
118
|
+
You can load Asciidoctor question in a terminal using the `-r` flag.
|
119
|
+
|
120
|
+
$ asciidoctor -r asciidoctor-question sample.adoc
|
121
|
+
|
122
|
+
You can also use Asciidoctor question with other converters, such as Asciidoctor PDF.
|
123
|
+
Asciidoctor-pdf is also loaded with the `-r` flag.
|
124
|
+
|
125
|
+
$ asciidoctor -r asciidoctor-question -r asciidoctor-pdf -b pdf sample.adoc
|
126
|
+
|
127
|
+
Or, you can invoke Asciidoctor and the PDF converter with the `asciidoctor-pdf` command.
|
128
|
+
The command implicitly sets the `-r` and `-b` flags for PDF output.
|
129
|
+
|
130
|
+
$ asciidoctor-pdf -r asciidoctor-question sample.adoc
|
data/Rakefile
ADDED
data/images/gap.png
ADDED
Binary file
|
data/images/mc.png
ADDED
Binary file
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'asciidoctor' unless defined? ::Asciidoctor::VERSION
|
2
|
+
require 'asciidoctor/extensions'
|
3
|
+
|
4
|
+
require_relative 'version'
|
5
|
+
|
6
|
+
module Asciidoctor
|
7
|
+
module Question
|
8
|
+
module Extensions
|
9
|
+
class BaseProcessor < Asciidoctor::Extensions::BlockProcessor
|
10
|
+
use_dsl
|
11
|
+
|
12
|
+
def self.inherited(subclass)
|
13
|
+
subclass.option :contexts, [:example, :literal, :open]
|
14
|
+
subclass.option :content_model, :simple
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_error(parent, err, source_lines)
|
18
|
+
lines = ['[NOTE]', '====', 'Fehler! ' + err, '====']
|
19
|
+
block = Asciidoctor::Parser.next_block Asciidoctor::Reader.new(lines), parent
|
20
|
+
block.blocks.push Asciidoctor::Parser.next_block Asciidoctor::Reader.new(['[source, asciidoc]', '----'] + source_lines + ['----']), block
|
21
|
+
block
|
22
|
+
end
|
23
|
+
|
24
|
+
def process_error_push(parent, err, source_lines)
|
25
|
+
parent.blocks.push process_error parent, err, source_lines
|
26
|
+
end
|
27
|
+
|
28
|
+
def post_answers(parent, tag)
|
29
|
+
id = tag[:id]
|
30
|
+
parent.blocks.push Asciidoctor::Block.new parent, :pass, :source => "
|
31
|
+
<p style=\"margin-bottom: 25px\">
|
32
|
+
<button onclick='resolve(#{id})'>resolve</button>
|
33
|
+
<button onclick='reset(#{id})'>reset</button>
|
34
|
+
</p>"
|
35
|
+
parent
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative '../extensions'
|
2
|
+
|
3
|
+
module Asciidoctor
|
4
|
+
module Question
|
5
|
+
|
6
|
+
class GAPBlockProcessor < Extensions::BaseProcessor
|
7
|
+
|
8
|
+
def process(parent, source, tag)
|
9
|
+
id = tag[:id]
|
10
|
+
err = nil
|
11
|
+
|
12
|
+
question = source.lines
|
13
|
+
|
14
|
+
question.map! do |line|
|
15
|
+
line.gsub /__([^_]+?)__/ do |value|
|
16
|
+
prepare_gap value.gsub('_', ''), tag
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
new_parent = Asciidoctor::Block.new parent, :open, {:attributes => {'id' => "question_gap_#{id}"}}
|
21
|
+
|
22
|
+
reader = Asciidoctor::Reader.new question
|
23
|
+
|
24
|
+
loop do
|
25
|
+
block = Asciidoctor::Parser.next_block reader, new_parent
|
26
|
+
break if block.nil?
|
27
|
+
|
28
|
+
if block.context == :listing
|
29
|
+
block.subs.push :macros
|
30
|
+
block.subs.push :quotes
|
31
|
+
end
|
32
|
+
new_parent.blocks.push block
|
33
|
+
end
|
34
|
+
|
35
|
+
if err.nil?
|
36
|
+
post_answers new_parent, tag
|
37
|
+
else
|
38
|
+
process_error_push new_parent, err, source.lines
|
39
|
+
end
|
40
|
+
|
41
|
+
new_parent
|
42
|
+
end
|
43
|
+
|
44
|
+
def prepare_gap(value, tag)
|
45
|
+
value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class PDFGAPBlockProcessor < GAPBlockProcessor
|
50
|
+
def prepare_gap(value, tag)
|
51
|
+
if tag[:solution] then
|
52
|
+
"`[red]## +++__#{value}__+++ ##`"
|
53
|
+
else
|
54
|
+
"+++ #{'_' * (value.size + 4)} +++"
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def post_answers(parent, tag)
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
class HTMLGAPBlockProcessor < GAPBlockProcessor
|
66
|
+
|
67
|
+
def prepare_gap(value, tag)
|
68
|
+
'+++<gap> <input type="text"/> <answer class="hidden">' + value + '</answer> </gap>+++'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require_relative '../extensions'
|
2
|
+
|
3
|
+
module Asciidoctor
|
4
|
+
module Question
|
5
|
+
|
6
|
+
class MultipleChoiceBlockProcessor < Extensions::BaseProcessor
|
7
|
+
|
8
|
+
name_positional_attributes :shuffle
|
9
|
+
|
10
|
+
def process(parent, source, tag)
|
11
|
+
id = tag[:id]
|
12
|
+
err = nil
|
13
|
+
question = Array.new
|
14
|
+
answers = Array.new ['[options=interactive]']
|
15
|
+
switch = false
|
16
|
+
|
17
|
+
source.lines.each do |line|
|
18
|
+
switch = true if line =~ /^-\s?\[/
|
19
|
+
if switch
|
20
|
+
answers.push line
|
21
|
+
else
|
22
|
+
question.push line
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
answers = prepare_answer_lines answers
|
27
|
+
|
28
|
+
new_parent = Asciidoctor::Block.new parent, :open, {:attributes => {'id' => "question_mc_#{id}"}}
|
29
|
+
|
30
|
+
reader = Asciidoctor::Reader.new(question)
|
31
|
+
loop do
|
32
|
+
block = Asciidoctor::Parser.next_block reader, new_parent
|
33
|
+
break if block.nil?
|
34
|
+
new_parent.blocks.push block
|
35
|
+
end
|
36
|
+
|
37
|
+
reader = Asciidoctor::Reader.new(answers)
|
38
|
+
answers_block = Asciidoctor::Parser.next_block reader, new_parent
|
39
|
+
if answers_block.nil?
|
40
|
+
err = 'Es sind keine Antworten vorhanden!'
|
41
|
+
end
|
42
|
+
|
43
|
+
if err.nil?
|
44
|
+
new_parent.blocks.push prepare_answers answers_block, tag
|
45
|
+
post_answers new_parent, tag
|
46
|
+
|
47
|
+
else
|
48
|
+
process_error_push new_parent, err, answers
|
49
|
+
end
|
50
|
+
new_parent
|
51
|
+
end
|
52
|
+
|
53
|
+
def prepare_answer_lines(lines)
|
54
|
+
lines
|
55
|
+
end
|
56
|
+
|
57
|
+
def prepare_answers(answers_block, tag)
|
58
|
+
answers_block.blocks.shuffle! if tag[:shuffle] == 'shuffle'
|
59
|
+
answers_block
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
class PDFMultipleChoiceBlockProcessor < MultipleChoiceBlockProcessor
|
65
|
+
def prepare_answers(answers_block, tag)
|
66
|
+
super
|
67
|
+
unless tag[:solution]
|
68
|
+
answers_block.blocks.each do |answer|
|
69
|
+
answer.attributes.delete('checked')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
answers_block
|
73
|
+
end
|
74
|
+
|
75
|
+
def post_answers(parent, tag)
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class HTMLMultipleChoiceBlockProcessor < MultipleChoiceBlockProcessor
|
81
|
+
|
82
|
+
def prepare_answer_lines(lines)
|
83
|
+
lines.map! do |answer|
|
84
|
+
if answer =~ /^-\s?\[/ then
|
85
|
+
answer.sub ']', '] +++ <span/> +++'
|
86
|
+
else
|
87
|
+
answer
|
88
|
+
end
|
89
|
+
end
|
90
|
+
lines
|
91
|
+
end
|
92
|
+
|
93
|
+
def prepare_answers(answers_block, tag)
|
94
|
+
super
|
95
|
+
id = tag[:id]
|
96
|
+
aid = -1
|
97
|
+
answers_block.attributes['id'] = "answers_mc_#{id}"
|
98
|
+
|
99
|
+
answers_block.blocks.each do |answer|
|
100
|
+
answer.attributes['id'] = "answer_mc_#{id}_#{aid += 1}"
|
101
|
+
end
|
102
|
+
answers_block
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
require_relative '../extensions'
|
3
|
+
require_relative '../multiple_choice/extension'
|
4
|
+
require_relative '../gap/extension'
|
5
|
+
require_relative './post_processor'
|
6
|
+
|
7
|
+
module Asciidoctor
|
8
|
+
module Question
|
9
|
+
class QuestionBlockProcessor < Extensions::BaseProcessor
|
10
|
+
name_positional_attributes [:type, :shuffle]
|
11
|
+
|
12
|
+
def initialize name = nil, config = {}
|
13
|
+
super name, config
|
14
|
+
@id = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def process(parent, source, tag)
|
18
|
+
block = nil
|
19
|
+
err = nil
|
20
|
+
|
21
|
+
type = tag[:type]
|
22
|
+
tag[:id] = @id = @id + 1
|
23
|
+
|
24
|
+
tag[:solution] = !parent.attributes['solution'].nil?
|
25
|
+
|
26
|
+
if type.nil?
|
27
|
+
err = 'Typ fehlt.'
|
28
|
+
end
|
29
|
+
|
30
|
+
if err.nil?
|
31
|
+
if type == 'mc' or type == 'multiplechoice' or type == 'multiple_choice'
|
32
|
+
block = process_question_mc parent, source, tag
|
33
|
+
elsif type == 'gap'
|
34
|
+
block = process_question_gap parent, source, tag
|
35
|
+
end
|
36
|
+
else
|
37
|
+
block = process_error parent, err, source.lines
|
38
|
+
end
|
39
|
+
|
40
|
+
block
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
class HTMLQuestionBlockProcessor < QuestionBlockProcessor
|
46
|
+
name_positional_attributes [:type, :shuffle]
|
47
|
+
|
48
|
+
def process_question_mc parent, source, tag
|
49
|
+
HTMLMultipleChoiceBlockProcessor.new.process parent, source, tag
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_question_gap parent, source, tag
|
53
|
+
HTMLGAPBlockProcessor.new.process parent, source, tag
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
class PDFQuestionBlockProcessor < QuestionBlockProcessor
|
59
|
+
name_positional_attributes [:type, :shuffle]
|
60
|
+
|
61
|
+
def process_question_mc parent, source, tag
|
62
|
+
PDFMultipleChoiceBlockProcessor.new.process parent, source, tag
|
63
|
+
end
|
64
|
+
|
65
|
+
def process_question_gap parent, source, tag
|
66
|
+
PDFGAPBlockProcessor.new.process parent, source, tag
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Asciidoctor
|
4
|
+
module Question
|
5
|
+
class HTMLPostProcessor < Asciidoctor::Extensions::Postprocessor
|
6
|
+
def process(document, output)
|
7
|
+
doc = Nokogiri::HTML(output)
|
8
|
+
head = doc.at_css 'head'
|
9
|
+
basedir = File.expand_path('../../../../', __FILE__)
|
10
|
+
file = File.open("#{basedir}/res/asciidoctor-question/question.css")
|
11
|
+
head.add_child("
|
12
|
+
<style id=\"question\">
|
13
|
+
#{file.read}
|
14
|
+
</style>
|
15
|
+
")
|
16
|
+
file.close
|
17
|
+
|
18
|
+
file = File.open("#{basedir}/res/asciidoctor-question/question.js")
|
19
|
+
head.add_child("<script type=\"text/javascript\">
|
20
|
+
#{file.read}
|
21
|
+
</script>")
|
22
|
+
file.close
|
23
|
+
|
24
|
+
questions = doc.css 'div[id*=question]'
|
25
|
+
questions.each do |question|
|
26
|
+
id = question['id']
|
27
|
+
parts = id.split '_'
|
28
|
+
question['id'] = "#{parts[0]}_#{parts[2]}"
|
29
|
+
question['data-type'] = parts[1]
|
30
|
+
end
|
31
|
+
|
32
|
+
answers = doc.css 'div[id*=question][data-type=mc] input[type="checkbox"]'
|
33
|
+
answers.each do |answer|
|
34
|
+
answer['data-correct'] = answer.key?('checked')
|
35
|
+
answer.delete('checked')
|
36
|
+
end
|
37
|
+
doc.to_html
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'extensions'
|
2
|
+
|
3
|
+
Asciidoctor::Extensions.register do
|
4
|
+
require_relative 'question/extension'
|
5
|
+
|
6
|
+
if document.basebackend? 'html' and not document.backend == 'pdf'
|
7
|
+
block Asciidoctor::Question::HTMLQuestionBlockProcessor, :question
|
8
|
+
postprocessor Asciidoctor::Question::HTMLPostProcessor
|
9
|
+
end
|
10
|
+
|
11
|
+
block Asciidoctor::Question::PDFQuestionBlockProcessor, :question if document.backend == 'pdf'
|
12
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'asciidoctor-question/question'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
.hidden {
|
2
|
+
display: none;
|
3
|
+
}
|
4
|
+
|
5
|
+
div[id*=question][data-type=gap] gap > input.incorrect {
|
6
|
+
font-weight: bold;
|
7
|
+
color: red;
|
8
|
+
}
|
9
|
+
|
10
|
+
|
11
|
+
div[id*=question][data-type=gap] gap > answer, div[id*=question][data-type=gap] gap > input.correct {
|
12
|
+
font-weight: bold;
|
13
|
+
color: green;
|
14
|
+
}
|
15
|
+
|
16
|
+
div[id*=question][data-type=mc] input[type="checkbox"].show ~ span::before {
|
17
|
+
display: inline;
|
18
|
+
width: 16px;
|
19
|
+
height: 16px;
|
20
|
+
}
|
21
|
+
|
22
|
+
div[id*=question][data-type=mc] input[type="checkbox"][data-correct="true"].show ~ span::before {
|
23
|
+
content: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSIxNnB4IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2cHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxwYXRoIGZpbGw9Im9saXZlZHJhYiIgc3Ryb2tlPSJvbGl2ZWRyYWIiIGQ9Ik0yMS42NTIsMy4yMTFjLTAuMjkzLTAuMjk1LTAuNzctMC4yOTUtMS4wNjEsMEw5LjQxLDE0LjM0ICBjLTAuMjkzLDAuMjk3LTAuNzcxLDAuMjk3LTEuMDYyLDBMMy40NDksOS4zNTFDMy4zMDQsOS4yMDMsMy4xMTQsOS4xMywyLjkyMyw5LjEyOUMyLjczLDkuMTI4LDIuNTM0LDkuMjAxLDIuMzg3LDkuMzUxICBsLTIuMTY1LDEuOTQ2QzAuMDc4LDExLjQ0NSwwLDExLjYzLDAsMTEuODIzYzAsMC4xOTQsMC4wNzgsMC4zOTcsMC4yMjMsMC41NDRsNC45NCw1LjE4NGMwLjI5MiwwLjI5NiwwLjc3MSwwLjc3NiwxLjA2MiwxLjA3ICBsMi4xMjQsMi4xNDFjMC4yOTIsMC4yOTMsMC43NjksMC4yOTMsMS4wNjIsMGwxNC4zNjYtMTQuMzRjMC4yOTMtMC4yOTQsMC4yOTMtMC43NzcsMC0xLjA3MUwyMS42NTIsMy4yMTF6Ii8+PC9zdmc+);
|
24
|
+
}
|
25
|
+
|
26
|
+
div[id*=question][data-type=mc] input[type="checkbox"][data-correct="false"].show ~ span::before {
|
27
|
+
content: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSIxNnB4IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2cHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxwYXRoIGZpbGw9Im1hcm9vbiIgc3Ryb2tlPSJtYXJvb24iIGQ9Ik0yMi4yNDUsNC4wMTVjMC4zMTMsMC4zMTMsMC4zMTMsMC44MjYsMCwxLjEzOWwtNi4yNzYsNi4yN2MtMC4zMTMsMC4zMTItMC4zMTMsMC44MjYsMCwxLjE0bDYuMjczLDYuMjcyICBjMC4zMTMsMC4zMTMsMC4zMTMsMC44MjYsMCwxLjE0bC0yLjI4NSwyLjI3N2MtMC4zMTQsMC4zMTItMC44MjgsMC4zMTItMS4xNDIsMGwtNi4yNzEtNi4yNzFjLTAuMzEzLTAuMzEzLTAuODI4LTAuMzEzLTEuMTQxLDAgIGwtNi4yNzYsNi4yNjdjLTAuMzEzLDAuMzEzLTAuODI4LDAuMzEzLTEuMTQxLDBsLTIuMjgyLTIuMjhjLTAuMzEzLTAuMzEzLTAuMzEzLTAuODI2LDAtMS4xNGw2LjI3OC02LjI2OSAgYzAuMzEzLTAuMzEyLDAuMzEzLTAuODI2LDAtMS4xNEwxLjcwOSw1LjE0N2MtMC4zMTQtMC4zMTMtMC4zMTQtMC44MjcsMC0xLjE0bDIuMjg0LTIuMjc4QzQuMzA4LDEuNDE3LDQuODIxLDEuNDE3LDUuMTM1LDEuNzMgIEwxMS40MDUsOGMwLjMxNCwwLjMxNCwwLjgyOCwwLjMxNCwxLjE0MSwwLjAwMWw2LjI3Ni02LjI2N2MwLjMxMi0wLjMxMiwwLjgyNi0wLjMxMiwxLjE0MSwwTDIyLjI0NSw0LjAxNXoiLz48L3N2Zz4=);
|
28
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
function resolve(questionId) {
|
2
|
+
var q = document.getElementById("question_" + questionId)
|
3
|
+
var type = q.getAttribute("data-type")
|
4
|
+
var elems
|
5
|
+
var pos
|
6
|
+
var answer
|
7
|
+
|
8
|
+
if(type == "mc") {
|
9
|
+
elems = q.getElementsByTagName("input")
|
10
|
+
for(pos = 0; pos < elems.length; pos++) {
|
11
|
+
answer = elems[pos]
|
12
|
+
answer.setAttribute("class", "show")
|
13
|
+
}
|
14
|
+
} else if(type == "gap") {
|
15
|
+
elems = q.getElementsByTagName("gap")
|
16
|
+
for(pos = 0; pos < elems.length; pos++) {
|
17
|
+
var gap = elems[pos]
|
18
|
+
var input = gap.getElementsByTagName("input")[0]
|
19
|
+
answer = gap.getElementsByTagName("answer")[0]
|
20
|
+
if(input.value == answer.textContent) {
|
21
|
+
input.setAttribute("class", "correct")
|
22
|
+
} else {
|
23
|
+
input.setAttribute("class", "incorrect")
|
24
|
+
answer.setAttribute("class", "")
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
function reset(questionId) {
|
31
|
+
var q = document.getElementById("question_" + questionId)
|
32
|
+
var type = q.getAttribute("data-type")
|
33
|
+
var elems
|
34
|
+
var pos
|
35
|
+
var answer
|
36
|
+
|
37
|
+
if(type == "mc") {
|
38
|
+
elems = q.getElementsByTagName("input")
|
39
|
+
for(pos = 0; pos < elems.length; pos++) {
|
40
|
+
answer = elems[pos]
|
41
|
+
answer.setAttribute("class", "")
|
42
|
+
}
|
43
|
+
} else if(type == "gap") {
|
44
|
+
elems = q.getElementsByTagName("gap")
|
45
|
+
for(pos = 0; pos < elems.length; pos++) {
|
46
|
+
var gap = elems[pos]
|
47
|
+
var input = gap.getElementsByTagName("input")[0]
|
48
|
+
answer = gap.getElementsByTagName("answer")[0]
|
49
|
+
input.setAttribute("class", "")
|
50
|
+
answer.setAttribute("class", "hidden")
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
data/test/test.adoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
[question, gap]
|
3
|
+
====
|
4
|
+
Lorem __ipsum__ dolor sit amet, consetetur __sadipscing__ elitr,
|
5
|
+
sed diam nonumy eirmod __tempor invidunt ut__ labore et dolore
|
6
|
+
magna aliquyam erat, sed diam voluptua. At vero eos et
|
7
|
+
accusam et justo duo dolores et ea rebum.
|
8
|
+
|
9
|
+
[source,ruby]
|
10
|
+
----
|
11
|
+
Stet clita kasd gubergren, no sea takimata __sanctus__ est Lorem ipsum dolor sit amet.
|
12
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
|
13
|
+
sed diam nonumy eirmod tempor __invidunt__ ut labore et
|
14
|
+
dolore magna aliquyam erat, sed diam voluptua.
|
15
|
+
----
|
16
|
+
|
17
|
+
At vero eos et __accusam__ et justo duo dolores et ea rebum.
|
18
|
+
Stet clita kasd gubergren, no sea takimata __sanctus__ est Lorem ipsum dolor sit amet.
|
19
|
+
====
|
20
|
+
|
21
|
+
[question, mc]
|
22
|
+
====
|
23
|
+
Das hier ist eine Frage:
|
24
|
+
----
|
25
|
+
test
|
26
|
+
----
|
27
|
+
|
28
|
+
- [ ] Hallo 1234
|
29
|
+
pkfsepgkdsjghü ojsoip jhsotjhotsjoh std oh sodn hodnh adinhididnhdtd dp dknwodh snmhd öndpishdod mdhopj
|
30
|
+
- [*] test
|
31
|
+
====
|
32
|
+
|
33
|
+
[question, mc]
|
34
|
+
....
|
35
|
+
====
|
36
|
+
test
|
37
|
+
====
|
38
|
+
|
39
|
+
- [ ] Hallo 1234
|
40
|
+
pkfsepgkdsjghü ojsoip jhsotjhotsjoh std oh sodn hodnh adinhididnhdtd dp dknwodh snmhd öndpishdod mdhopj
|
41
|
+
- [*] test
|
42
|
+
....
|
43
|
+
|
44
|
+
[question, mc]
|
45
|
+
--
|
46
|
+
Das hier ist eine Frage:
|
47
|
+
====
|
48
|
+
test
|
49
|
+
====
|
50
|
+
|
51
|
+
- [ ] Hallo 1234
|
52
|
+
pkfsepgkdsjghü ojsoip jhsotjhotsjoh std oh sodn hodnh adinhididnhdtd dp dknwodh snmhd öndpishdod mdhopj
|
53
|
+
- [*] test
|
54
|
+
--
|
data/test/test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asciidoctor-question
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marcel Hoppe
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: asciidoctor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.5'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: nokogiri
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.6'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.6'
|
83
|
+
description: Asciidoctor questioning extension.rb
|
84
|
+
email:
|
85
|
+
- marcel.hoppe@mni.thm.de
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- CHANGELOG.adoc
|
91
|
+
- LICENSE.adoc
|
92
|
+
- README.adoc
|
93
|
+
- Rakefile
|
94
|
+
- images/gap.png
|
95
|
+
- images/mc.png
|
96
|
+
- lib/asciidoctor-question.rb
|
97
|
+
- lib/asciidoctor-question/extensions.rb
|
98
|
+
- lib/asciidoctor-question/gap/extension.rb
|
99
|
+
- lib/asciidoctor-question/multiple_choice/extension.rb
|
100
|
+
- lib/asciidoctor-question/question.rb
|
101
|
+
- lib/asciidoctor-question/question/extension.rb
|
102
|
+
- lib/asciidoctor-question/question/post_processor.rb
|
103
|
+
- lib/asciidoctor-question/version.rb
|
104
|
+
- res/asciidoctor-question/question.css
|
105
|
+
- res/asciidoctor-question/question.js
|
106
|
+
- test/test.adoc
|
107
|
+
- test/test.rb
|
108
|
+
homepage: https://github.com/hobbypunk90/asciidoctor-question
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '2.3'
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '2'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
requirements: []
|
130
|
+
rubyforge_project:
|
131
|
+
rubygems_version: 2.6.8
|
132
|
+
signing_key:
|
133
|
+
specification_version: 4
|
134
|
+
summary: An extension.rb for asciidoctor-question that adds support for multiple choice
|
135
|
+
and gap questions
|
136
|
+
test_files:
|
137
|
+
- test/test.adoc
|
138
|
+
- test/test.rb
|