asciidoctor-question 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|