├── source ├── stylesheets │ ├── quiz-curbed.css.scss │ ├── .DS_Store │ ├── quiz-eater.css.scss │ ├── quiz-polygon.css.scss │ ├── quiz-sbnation.css.scss │ ├── flowchart.css.scss │ ├── quiz-verge.css.scss │ ├── quiz-vox.css.scss │ ├── quiz-racked.css.scss │ ├── quiz-fashion.css.scss │ ├── quiz.css.scss │ └── quiz-generator.css.scss ├── images │ ├── qq.png │ ├── voxlogo.png │ └── quartetLOL.jpg ├── racked.html.erb ├── layouts │ ├── demo.erb │ └── layout.erb ├── index.html.erb ├── javascripts │ ├── fashion-quiz.js │ ├── getdata.js │ ├── binary.js │ ├── quiz.js │ ├── flowchart.js │ ├── tabletop.js │ └── jquery.min.js └── demo.html.erb ├── Rakefile ├── .gitignore ├── config.ru ├── Gemfile ├── config.rb ├── Gemfile.lock └── README.md /source/stylesheets/quiz-curbed.css.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | namespace :assets do 2 | task :precompile do 3 | sh 'middleman build' 4 | end 5 | end -------------------------------------------------------------------------------- /source/images/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voxmedia/quiz-generator/HEAD/source/images/qq.png -------------------------------------------------------------------------------- /source/images/voxlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voxmedia/quiz-generator/HEAD/source/images/voxlogo.png -------------------------------------------------------------------------------- /source/images/quartetLOL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voxmedia/quiz-generator/HEAD/source/images/quartetLOL.jpg -------------------------------------------------------------------------------- /source/stylesheets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voxmedia/quiz-generator/HEAD/source/stylesheets/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore bundler config 2 | /.bundle 3 | 4 | # Ignore the build directory 5 | /build 6 | 7 | # Ignore Sass' cache 8 | /.sass-cache 9 | 10 | # Ignore this .cache 11 | /.cache 12 | # Dont ignore these apparently, dumb Tate /.ruby-version 13 | 14 | # Ignore .DS_store file 15 | .DS_Store 16 | source/.DS_Store 17 | 18 | /test -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require 'rack' 2 | require 'rack/contrib/try_static' 3 | 4 | # Serve files from the build directory 5 | use Rack::TryStatic, 6 | root: 'build', 7 | urls: %w[/], 8 | try: ['.html', 'index.html', '/index.html'] 9 | 10 | run lambda{ |env| 11 | four_oh_four_page = File.expand_path("../build/index.html", __FILE__) 12 | [ 404, { 'Content-Type' => 'text/html'}, [ File.read(four_oh_four_page) ]] 13 | } -------------------------------------------------------------------------------- /source/racked.html.erb: -------------------------------------------------------------------------------- 1 |
19 | <%= yield %>
20 |
21 |
--------------------------------------------------------------------------------
/source/stylesheets/quiz-eater.css.scss:
--------------------------------------------------------------------------------
1 | $font-stack: 'Whitney Regular', Arial, sans-serif;
2 | $question-font: 'Glober', Georgia, serif;
3 | $purple: #6d0028;
4 |
5 | // Container for generated quiz
6 | .quiz-container {
7 | font-family: $font-stack;
8 | text-align: center;
9 | border-top: 7px solid $purple;
10 | padding-top: 20px;
11 | }
12 |
13 | // Text for each question
14 | .qq-question {
15 | font-family: $question-font;
16 | color: #000000;
17 | font-size: 1.5em;
18 | margin: 0% auto;
19 | margin-bottom: 20px;
20 | font-weight: bolder;
21 | }
22 |
23 | // Answer options for each question
24 | ol.answers > li {
25 | font-family: $font-stack;
26 | font-size: 1em;
27 |
28 | &:before {
29 | font-family: $question-font;
30 | font-weight: bold;
31 | color: #FFFFFF;
32 | background-color: $purple;
33 | width: 30px;
34 | }
35 | &:hover {
36 | background-color: #EEEDED;
37 | }
38 | }
39 |
40 | // Buttons
41 | .qq-button {
42 | font-family: ff-din-web-condensed, Helvetica, sans-serif;
43 | color: #FFFFFF;
44 | font-weight: 400;
45 | background-color: $purple;
46 | &:hover {
47 | background-color: $purple !important;
48 | }
49 | }
50 |
51 | // Submit button color when an answer is selected
52 | .submit-highlight {
53 | background-color: #e60000;
54 | }
55 |
56 | // Highlights selected answer
57 | .selected {
58 | background-color: #ffe8e1;
59 | }
60 |
61 | // Checking selected anhswer
62 | .answer p {
63 | font-family: $font-stack;
64 | font-size: 0.9em;
65 | &:first-child {
66 | font-family: $question-font;
67 | }
68 | }
69 |
70 | // Social media buttons on final scorecard
71 | #social-media ul li a svg {
72 | &:hover {
73 | fill: $purple;
74 | }
75 | path:hover {
76 | fill: #FFFFFF;
77 | }
78 | }
79 |
80 | // Hyperlinks
81 | .answer a {
82 | color: $purple;
83 | text-decoration: none;
84 | &:hover {
85 | color: #000000;
86 | }
87 | }
--------------------------------------------------------------------------------
/source/stylesheets/quiz-polygon.css.scss:
--------------------------------------------------------------------------------
1 | $font-stack: 'Gotham SSm A', 'Gotham SSm B', Arial, sans-serif;
2 | $purple: #3F1E45;
3 |
4 | // Container for generated quiz
5 | .quiz-container {
6 | font-family: $font-stack;
7 | border-top: 3px solid #000000;
8 | }
9 |
10 | // Text for each question
11 | .qq-question {
12 | font-family: $font-stack;
13 | font-weight: bold;
14 | color: #000000;
15 | font-size: 1.5em;
16 | margin: 0% auto;
17 | margin-bottom: 20px;
18 | }
19 |
20 | // Description for each question
21 | .qq-description {
22 | font-family: $font-stack;
23 | padding: 20px 20px 0px 20px;
24 | }
25 |
26 | // Answer options for each question
27 | ol.answers > li {
28 | font-family: $font-stack;
29 |
30 | &:before {
31 | font-family: $font-stack;
32 | font-style: italic;
33 | color: #FFFFFF;
34 | background-color: $purple;
35 | width: 30px;
36 | }
37 | &:hover {
38 | background-color: #EBEBEC;
39 | }
40 | }
41 |
42 | // Buttons
43 | .qq-button {
44 | font-family: $font-stack;
45 | font-style: italic;
46 | font-weight: 800;
47 | color: #FFFFFF;
48 | background-color: #FF0052;
49 | width: 180px;
50 | &:hover {
51 | background-color: $purple !important;
52 | }
53 | }
54 |
55 | // Highlights selected answer
56 | .selected {
57 | background-color: #DFDFE0;
58 | }
59 |
60 | // Submit button color when an answer is selected
61 | .submit-highlight {
62 | background-color: #CD1949;
63 | }
64 |
65 | // Checking selected answer
66 | .answer p:first-child {
67 | font-family: $font-stack;
68 | }
69 |
70 | // Social media buttons on final scorecard
71 | #social-media ul li a svg {
72 | &:hover {
73 | fill: #ED1C55;
74 | }
75 | path:hover {
76 | fill: #FFFFFF;
77 | }
78 | fill: $purple;
79 | }
80 |
81 | // Hyperlinks
82 | .answer a {
83 | color: #FF0052;
84 | text-decoration: none;
85 | &:hover {
86 | text-decoration: underline;
87 | }
88 | }
89 |
90 | // FLowchart selection
91 | .flowchart-selected {
92 | background-color: $purple !important;
93 | color: #FFFFFF !important;
94 | }
95 |
96 | // Flowchart button hover
97 | .flowchart-button {
98 | &:hover {
99 | background-color: $purple;
100 | color: #FFFFFF;
101 | }
102 | }
--------------------------------------------------------------------------------
/source/stylesheets/quiz-sbnation.css.scss:
--------------------------------------------------------------------------------
1 | $font-stack: 'Gotham SSm A', 'Gotham SSm B', Arial, sans-serif;
2 | $question-font: 'Sentinel SSm A', 'Sentinel SSm B', Georgia, serif;
3 | $red: #C52327;
4 |
5 | // Container for generated quiz
6 | .quiz-container {
7 | font-family: $font-stack;
8 | text-align: center;
9 | border-top: 7px solid $red;
10 | padding-top: 20px;
11 | }
12 |
13 | // Text for each question
14 | .qq-question {
15 | font-family: $question-font;
16 | color: #000000;
17 | font-size: 1.5em;
18 | margin: 0% auto;
19 | margin-bottom: 20px;
20 | }
21 |
22 | // Description for each question
23 | .qq-description {
24 | font-family: $font-stack;
25 | padding: 20px 10px 0px 10px;
26 | }
27 |
28 | // Answer options for each question
29 | ol.answers > li {
30 | font-family: $font-stack;
31 | font-size: 0.9em;
32 |
33 | &:before {
34 | font-family: $question-font;
35 | font-weight: bold;
36 | color: #FFFFFF;
37 | background-color: $red;
38 | width: 30px;
39 | }
40 | &:hover {
41 | background-color: #EEEDED;
42 | }
43 | }
44 |
45 | // Buttons
46 | .qq-button {
47 | font-family: ff-din-web-condensed, Helvetica, sans-serif;
48 | color: #FFFFFF;
49 | font-weight: 800;
50 | background-color: #000000;
51 | &:hover {
52 | background-color: $red !important;
53 | }
54 | }
55 |
56 | // Submit button color when an answer is selected
57 | .submit-highlight {
58 | background-color: #6D6E70;
59 | }
60 |
61 | // Checking selected answer
62 | .answer p {
63 | font-family: $font-stack;
64 | font-size: 0.9em;
65 | &:first-child {
66 | font-family: $question-font;
67 | }
68 | }
69 |
70 | // Social media buttons on final scorecard
71 | #social-media ul li a svg {
72 | &:hover {
73 | fill: $red;
74 | }
75 | path:hover {
76 | fill: #FFFFFF;
77 | }
78 | }
79 |
80 | // Hyperlinks
81 | .answer a {
82 | color: $red;
83 | text-decoration: none;
84 | &:hover {
85 | text-decoration: underline;
86 | }
87 | }
88 |
89 | // FLowchart selection
90 | .flowchart-selected {
91 | background-color: $red !important;
92 | color: #FFFFFF !important;
93 | }
94 |
95 | // Flowchart button hover
96 | .flowchart-button {
97 | &:hover {
98 | background-color: $red;
99 | color: #FFFFFF;
100 | }
101 | }
--------------------------------------------------------------------------------
/source/stylesheets/flowchart.css.scss:
--------------------------------------------------------------------------------
1 | // Mixin for button hover transitions
2 | @mixin transition($transition-time) {
3 | -o-transition: $transition-time;
4 | -ms-transition: $transition-time;
5 | -moz-transition: $transition-time;
6 | -webkit-transition: $transition-time;
7 | transition: $transition-time;
8 | }
9 |
10 | $font-stack: 'Alight Sans', sans-serif;
11 | $question-font: 'Balto', sans-serif;
12 |
13 | .quiz-container {
14 | font-family: $font-stack;
15 | text-align: center;
16 | background-color: #FFFFFF;
17 | margin: 0 auto;
18 | max-width: 770px;
19 | width: 100%;
20 | padding-bottom: 1em;
21 | }
22 |
23 | .choices {
24 | text-align: center;
25 | }
26 |
27 | div.buttons {
28 | display:inline;
29 | }
30 |
31 | button.flowchart-button {
32 | @include transition(0.2s);
33 | font-family: Helvetica, sans-serif !important;
34 | font-size: .9em;
35 | font-weight: 100;
36 | color: #414141;
37 | background-color: #ececec;
38 | cursor: pointer;
39 | width: 120px;
40 | margin: 0.1em 1em 0.4em 0;
41 | border: 0;
42 | padding: 12px 0px;
43 | padding: 8px 10px;
44 |
45 | &:hover {
46 | background-color: #f37b21;
47 | }
48 | }
49 |
50 | p.down-arrow {
51 | margin: 0 auto;
52 | width: 100%;
53 | }
54 |
55 | .question {
56 | margin-top: 2.5em !important;
57 | margin-bottom: 0.4em;
58 | padding: 0 0.6em 0.6em;
59 | p {
60 | font-family: $question-font;
61 | font-size: 1.2em;
62 | font-weight: 400;
63 | }
64 | }
65 |
66 | .scorecard {
67 | margin-top: 15px;
68 | }
69 |
70 | .last {
71 | margin: 0 auto;
72 | margin-top: 2em;
73 | width: 70%;
74 | min-width: 200px;
75 | border-top: 1px solid #ececec;
76 |
77 | p {
78 | margin-top: 2em;
79 | margin-bottom: 0px;
80 | line-height: 1.5em;
81 | }
82 | }
83 |
84 | #social-media {
85 | padding: 10px;
86 | }
87 |
88 | // Social media buttons on final scorecard
89 | #social-media ul {
90 | text-align: center;
91 | list-style-type: none;
92 | margin: 0;
93 | padding: 0px;
94 | margin-bottom: 10px;
95 | li {
96 | display: inline-block;
97 | a {
98 | text-decoration: none;
99 | svg {
100 | height: 2em;
101 | width: 2em;
102 | margin-right: 1em;
103 | }
104 | }
105 | }
106 | }
--------------------------------------------------------------------------------
/source/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Quiz QuartetUse this Google Spreadsheet template to write your quiz.
18 |Once you're done editing, publish the spreadsheet to the web. Under the "File" menu, select "Publish to the Web." Click "Start Publishing" and copy the URL to build the quiz.
19 |Want to test it out? Try this spreadsheet:
Copy and paste your spreadsheet's URL here:
23 | 24 |' + input[currentQuestion].a + "
' + input[currentQuestion].b + "
' + input[currentQuestion].c + "
' + input[currentQuestion].d + "
' + input[currentQuestion].e + "
' + input[currentQuestion].f + "
You are " + percentage + "% " + scores[i].key + "
"); 91 | } 92 | } 93 | 94 | $(document).ready(function(){ 95 | getSpreadSheet(); 96 | }); -------------------------------------------------------------------------------- /source/stylesheets/quiz-fashion.css.scss: -------------------------------------------------------------------------------- 1 | // Mixin for button hover transitions 2 | @mixin transition($transition-time) { 3 | -o-transition: $transition-time; 4 | -ms-transition: $transition-time; 5 | -moz-transition: $transition-time; 6 | -webkit-transition: $transition-time; 7 | transition: $transition-time; 8 | } 9 | 10 | // Container for generated quiz 11 | .quiz-container { 12 | text-align: center; 13 | background-color: #ffffff; 14 | margin: 0% auto; 15 | width: 100%; 16 | max-width: 770px; 17 | margin-top: 20px; 18 | margin-bottom: 10px; 19 | padding-bottom: 60px; 20 | padding-top: 20px; 21 | } 22 | 23 | // Each quiz question 24 | .qq-question { 25 | font-size: 1.17em; 26 | max-width: 80%; 27 | margin: 0% auto; 28 | margin-top: 20px !important; 29 | line-height: 1.2; 30 | } 31 | 32 | // Description for each question 33 | .qq-description { 34 | font-size: 0.6em; 35 | font-weight: 300; 36 | text-align: left; 37 | line-height: 1.5; 38 | text-transform: none; 39 | font-style: normal; 40 | 41 | } 42 | 43 | // Padding for question text 44 | .question { 45 | padding-top: 10px; 46 | } 47 | 48 | // Shows user's progress throughout quiz (i.e. question 3/5) 49 | .progress { 50 | font-size: 11px; 51 | text-align: right; 52 | position: relative; 53 | right: 30px; 54 | } 55 | 56 | // Answer options (A, B, C, D) 57 | ol.answers { 58 | font-size: 0.9em; 59 | list-style-type: none; 60 | cursor: pointer; 61 | counter-reset: li-counter; 62 | position: relative; 63 | // width: 80%; 64 | // max-width: 500px; 65 | margin-bottom: 50px; 66 | padding: 0px; 67 | > li { 68 | &:before { 69 | font-size: 1em; 70 | text-align: center; 71 | cursor: pointer; 72 | content: counter(li-counter); 73 | counter-increment: li-counter; 74 | display: inline-block; 75 | width: 30px; 76 | margin-right: 10px; 77 | padding: 5px 0px 5px 0px; 78 | } 79 | @include transition(0.2s); 80 | text-align: left; 81 | margin: 20px 0px; 82 | } 83 | } 84 | 85 | // Button styles 86 | .qq-button { 87 | @include transition(0.2s); 88 | font-size: .9em; 89 | text-transform: uppercase; 90 | line-height: 1; 91 | display: inline-block; 92 | cursor: pointer; 93 | width: 160px; 94 | margin: 2px 5px; 95 | padding: .7em .7em .6em; 96 | border: 0; 97 | } 98 | 99 | .next:hover { 100 | background: transparent; 101 | } 102 | 103 | // Highlights selected answer 104 | .selected { 105 | background-color: #dfdfe0; 106 | font-weight: bold; 107 | } 108 | 109 | // Displays final scorecard 110 | .scorecard { 111 | display:block !important; 112 | } 113 | 114 | .score { 115 | font-size: .8em; 116 | float: right; 117 | padding-right: 7%; 118 | } 119 | 120 | // Social media buttons on final scorecard 121 | #social-media ul { 122 | text-align: center; 123 | list-style-type: none; 124 | margin: 0; 125 | padding: 0; 126 | margin-bottom: 10px; 127 | li { 128 | display: inline-block; 129 | a { 130 | text-decoration: none; 131 | svg { 132 | height: 2em; 133 | width: 3.4em; 134 | margin-right: 1em; 135 | } 136 | } 137 | } 138 | } 139 | 140 | // Submitted answer and feedback 141 | .answer { 142 | margin: 0% auto; 143 | width: 90%; 144 | max-width: 550px; 145 | margin-top: 20px !important; 146 | p { 147 | &:first-child { 148 | font-weight: bold; 149 | font-size: 1.2em; 150 | display: inline-block; 151 | width: 100%; 152 | padding-top: 30px; 153 | padding-bottom: 0px; 154 | border-top: 1px solid #000000; 155 | } 156 | &:nth-child(2) { 157 | margin: 0% auto; 158 | display: block; 159 | width: 100%; 160 | padding-top: 0px; 161 | padding-bottom: 20px; 162 | } 163 | } 164 | } 165 | 166 | // Text for each submitted answer 167 | .answer > p { 168 | margin: 0px 0px 20px 0px !important; 169 | } 170 | 171 | // Text on final scorecard 172 | .scorecard p { 173 | &:nth-child(1) { 174 | font-size: 1.2em; 175 | font-weight: bold; 176 | line-height: 1em !important; 177 | display: inline-block; 178 | margin-top: 45px; 179 | } 180 | &:nth-child(2) { 181 | font-size: 3em; 182 | font-weight: bold; 183 | margin-bottom: 40px; 184 | margin-top: 5px; 185 | } 186 | } -------------------------------------------------------------------------------- /source/stylesheets/quiz.css.scss: -------------------------------------------------------------------------------- 1 | // Mixin for button hover transitions 2 | @mixin transition($transition-time) { 3 | -o-transition: $transition-time; 4 | -ms-transition: $transition-time; 5 | -moz-transition: $transition-time; 6 | -webkit-transition: $transition-time; 7 | transition: $transition-time; 8 | } 9 | 10 | // Container for generated quiz 11 | .quiz-container { 12 | text-align: center; 13 | background-color: #ffffff; 14 | margin: 0% auto; 15 | width: 100%; 16 | max-width: 770px; 17 | margin-top: 20px; 18 | margin-bottom: 10px; 19 | padding-bottom: 60px; 20 | padding-top: 20px; 21 | } 22 | 23 | // Each quiz question 24 | .qq-question { 25 | font-size: 1.17em; 26 | max-width: 80%; 27 | margin: 0% auto; 28 | margin-top: 20px !important; 29 | line-height: 1.2; 30 | } 31 | 32 | // Description for each question 33 | .qq-description { 34 | font-size: 0.6em; 35 | font-weight: 300; 36 | text-align: left; 37 | line-height: 1.5; 38 | text-transform: none; 39 | font-style: normal; 40 | 41 | } 42 | 43 | // Padding for question text 44 | .question { 45 | padding-top: 10px; 46 | } 47 | 48 | // Shows user's progress throughout quiz (i.e. question 3/5) 49 | .progress { 50 | font-size: 11px; 51 | text-align: right; 52 | position: relative; 53 | right: 30px; 54 | } 55 | 56 | // Answer options (A, B, C, D) 57 | ol.answers { 58 | font-size: 0.9em; 59 | list-style-type: none; 60 | cursor: pointer; 61 | counter-reset: li-counter; 62 | position: relative; 63 | margin: 0px auto; 64 | width: 80%; 65 | max-width: 500px; 66 | margin-bottom: 50px; 67 | padding: 0px; 68 | > li { 69 | &:before { 70 | font-size: 1em; 71 | text-align: center; 72 | cursor: pointer; 73 | content: counter(li-counter); 74 | counter-increment: li-counter; 75 | display: inline-block; 76 | width: 30px; 77 | margin-right: 10px; 78 | padding: 5px 0px 5px 0px; 79 | } 80 | @include transition(0.2s); 81 | text-align: left; 82 | margin: 20px 0px; 83 | } 84 | } 85 | 86 | // Button styles 87 | .qq-button { 88 | @include transition(0.2s); 89 | font-size: .9em; 90 | text-transform: uppercase; 91 | line-height: 1; 92 | display: inline-block; 93 | cursor: pointer; 94 | width: 160px; 95 | margin: 2px 5px; 96 | padding: .7em .7em .6em; 97 | border: 0; 98 | } 99 | 100 | .next:hover { 101 | background: transparent; 102 | } 103 | 104 | // Highlights selected answer 105 | .selected { 106 | background-color: #dfdfe0; 107 | font-weight: bold; 108 | } 109 | 110 | // Displays final scorecard 111 | .scorecard { 112 | display:block !important; 113 | } 114 | 115 | .score { 116 | font-size: .8em; 117 | float: right; 118 | padding-right: 7%; 119 | } 120 | 121 | // Social media buttons on final scorecard 122 | #social-media ul { 123 | text-align: center; 124 | list-style-type: none; 125 | margin: 0; 126 | padding: 0; 127 | margin-bottom: 10px; 128 | li { 129 | display: inline-block; 130 | a { 131 | text-decoration: none; 132 | svg { 133 | height: 2em; 134 | width: 3.4em; 135 | margin-right: 1em; 136 | } 137 | } 138 | } 139 | } 140 | 141 | // Submitted answer and feedback 142 | .answer { 143 | margin: 0% auto; 144 | width: 90%; 145 | max-width: 550px; 146 | margin-top: 20px !important; 147 | p { 148 | &:first-child { 149 | font-weight: bold; 150 | font-size: 1.2em; 151 | display: inline-block; 152 | width: 100%; 153 | padding-top: 30px; 154 | padding-bottom: 0px; 155 | border-top: 1px solid #000000; 156 | } 157 | &:nth-child(2) { 158 | margin: 0% auto; 159 | display: block; 160 | width: 100%; 161 | padding-top: 0px; 162 | padding-bottom: 20px; 163 | } 164 | } 165 | } 166 | 167 | // Text for each submitted answer 168 | .answer > p { 169 | margin: 0px 0px 20px 0px !important; 170 | } 171 | 172 | // Text on final scorecard 173 | .scorecard p { 174 | &:nth-child(1) { 175 | font-size: 1.2em; 176 | font-weight: bold; 177 | line-height: 1em !important; 178 | display: inline-block; 179 | margin-top: 45px; 180 | } 181 | &:nth-child(2) { 182 | font-size: 3em; 183 | font-weight: bold; 184 | margin-bottom: 40px; 185 | margin-top: 5px; 186 | } 187 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Quiz Quartet 2 | ========== 3 | 4 | Quiz Quartet was built to automate the process for generating a quiz so no developer has to be involved and write repetitive code! Check out the project at [http://quiz-generator.herokuapp.com](http://quiz-generator.herokuapp.com) 5 | 6 | 7 | ## Running it locally 8 | 9 | This app uses Middleman, so cd to your project directory and just run: 10 | 11 | ##### Install Middleman 12 | 13 | `gem install middleman` 14 | 15 | ##### Install gems 16 | 17 | `bundle install` 18 | 19 | ##### Run server 20 | 21 | `bundle exec middleman server` 22 | 23 | ##### Generate static site 24 | 25 | `bundle exec middleman build` 26 | 27 | 28 | ## How does the tool work? 29 | 30 | The quiz tool is powered by (you guessed it!) Google Spreadsheets. Editors use a Google Spreadsheet Template to input the content of the quiz. For each question, they enter the question text, four choices, an optional question description, the correct answer, incorrect message, correct message and a hint. Once the editor is done, they publish the spreadsheet to the web and grab its public URL. 31 | 32 | The editor then feeds the spreadsheet URL into our authoring tool, which uses Tabletop.js to collect the spreadsheet data. In order to make the tool more reliable, the authoring tool uses Tabletop.js to collect the spreadsheet data into a JSON object, which is then attached to the embed code. This means that the quiz embed code will need to be regenerated every time a change is made in the spreadsheet, but the quiz will be more stable since it does not rely on accessing Google Spreadsheets every time it loads. 33 | 34 | Next, the editor picks from one of Vox Media’s verticals (the tool currently supports Vox.com, SB Nation, The Verge, Polygon, Eater and Racked). A vertical-specific stylesheet URL is then generated, e.g. quiz-vox.css. The stylesheet, together with the quiz data, is parsed together with a script tag using the quiz.js library. All of these files are currently hosted on Amazon S3. Now, editors can copy and paste the embed code into the CMS and voilà -- an interactive quiz without touching any code! 35 | 36 | 37 | 38 | ## How does the quiz work? 39 | The quiz dynamically generates an array of multiple choice questions from a JSON object. Users’ answers are highlighted when selected, then the chosen string is compared to the correct answer. Users can also see a hint for each question. Scores are incremented if the user answers correctly, and the final result is displayed at the end of the quiz for users to share on social media. 40 | 41 | 42 | 43 | ## What’s next? 44 | The app is fully functional, but we would like to add more options for creating different kinds of quizzes (true/false, flowchart-ish). We’d also like to make options for inserting images/video/audio within questions, answers, and hints (as our project is currently completely text-based). We’d also like to polish/write better Javascript! 45 | 46 | 47 | ## License 48 | 49 | Copyright (c) 2014 Vox Media Inc., KK Rebecca Lai, Nicole Zhu, Adam Baumgartner 50 | 51 | BSD license 52 | 53 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 54 | 55 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 56 | 57 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 58 | 59 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 60 | 61 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 | -------------------------------------------------------------------------------- /source/stylesheets/quiz-generator.css.scss: -------------------------------------------------------------------------------- 1 | // Font variables 2 | $font-stack: 'Open Sans', Helvetica, sans-serif; 3 | $orange: #f37b21; 4 | $black: #323132; 5 | $subheading-size: 0.8em; 6 | $bold: 800; 7 | 8 | // Sets background image and fonts 9 | body { 10 | font-family: $font-stack; 11 | color: #ffffff; 12 | color: $black; 13 | top: 0; 14 | left: 0; 15 | background-image: url(https://farm3.staticflickr.com/2906/14334201187_ec89d42b0a_o.jpg); 16 | background-repeat: repeat; 17 | background-attachment: fixed; 18 | background-position: center bottom; 19 | background-size: 100%; 20 | margin: 0px !important; 21 | margin-right: 0px; 22 | padding: 0px; 23 | } 24 | 25 | // Positioning Vox logo in upper right corner 26 | .vox-logo { 27 | position: absolute; 28 | top: 20px; 29 | left: 20px; 30 | z-index: 6; 31 | &:hover { 32 | opacity: 0.7; 33 | } 34 | } 35 | 36 | // Quiz Quartet text and icon positioning 37 | .quiz-quartet h1 { 38 | font-family: $font-stack; 39 | font-weight: $bold; 40 | font-size: 4em; 41 | color: #ffffff; 42 | text-align: center; 43 | z-index: 3 !important; 44 | margin: 0; 45 | padding: 50px 0px 50px 0px; 46 | > img { 47 | width: 56px; 48 | margin-bottom: -9px; 49 | } 50 | } 51 | 52 | // Container for quiz generator 53 | .container { 54 | position: relative; 55 | z-index: 10!important; 56 | background-color: #ffffff; 57 | margin: 0px; 58 | padding: 0px !important; 59 | } 60 | 61 | // Subheadings for quiz generator steps 62 | h5 { 63 | font-family: $font-stack; 64 | font-weight: $bold; 65 | font-size: $subheading-size; 66 | color: #000000; 67 | text-align: left; 68 | text-transform: uppercase; 69 | display: block; 70 | width: 70%; 71 | margin: 0% auto; 72 | margin-top: 60px; 73 | margin-bottom: 30px; 74 | padding: 5px 0% 5px 0%; 75 | border-bottom: 2px solid $orange; 76 | } 77 | 78 | // Text dividers (create quiz, preview quiz) 79 | h4 { 80 | font-family: $font-stack; 81 | font-weight: $bold; 82 | text-transform: uppercase; 83 | font-size: $subheading-size; 84 | color: #ffffff; 85 | text-align: left; 86 | width: 85%; 87 | display: block; 88 | background-color: $orange; 89 | padding: 5px 0px 5px 15%; 90 | border: 0px; 91 | &:first-child { 92 | margin: 0px 0px 30px 0px; 93 | } 94 | &:last-child { 95 | margin: 60px 0px 0px 0px; 96 | } 97 | } 98 | 99 | // Text under each subheading 100 | p { 101 | color: $black; 102 | display: block; 103 | width: 70%; 104 | margin: 0% auto; 105 | margin-bottom: 15px; 106 | } 107 | 108 | // Options for different verticals' stylesheets 109 | form { 110 | color: $black; 111 | display: block; 112 | width: 70%; 113 | margin: 0% auto; 114 | margin-bottom: 15px; 115 | padding-bottom: 20px; 116 | } 117 | 118 | // Links style 119 | a { 120 | text-decoration: none; 121 | -o-transition: .1s; 122 | -ms-transition: .1s; 123 | -moz-transition: .1s; 124 | -webkit-transition: .1s; 125 | transition: .1s; 126 | &:hover { 127 | color: #404041; 128 | } 129 | } 130 | 131 | // Link to quiz templates 132 | .template { 133 | background-color: #F37B21; 134 | color: #FFFFFF; 135 | } 136 | 137 | // 'Generate Your Quiz' button 138 | button { 139 | font-family: Helvetica; 140 | font-weight: lighter; 141 | font-size: 0.9em; 142 | text-decoration: none; 143 | text-transform: uppercase; 144 | color: #fff; 145 | text-align: center; 146 | width: 225px; 147 | background-color: #f27421; 148 | display: inline-block; 149 | cursor: pointer; 150 | margin: 0% auto; 151 | margin-top: 15px; 152 | padding: 12px 0px; 153 | padding: 8px 20px; 154 | border: 0; 155 | -o-transition: .2s; 156 | -ms-transition: .2s; 157 | -moz-transition: .2s; 158 | -webkit-transition: .2s; 159 | transition: .2s; 160 | &:hover { 161 | background-color: #404041; 162 | } 163 | } 164 | 165 | label { 166 | margin: 0 10px 0 5px; 167 | } 168 | 169 | // Preview of generated quiz 170 | .quiz-preview { 171 | background-color: transparent; 172 | z-index: 6!important; 173 | padding: 75px 0px 30px 0px; 174 | } 175 | 176 | // Embed code textarea 177 | textarea { 178 | color: #ffffff; 179 | background-color: #58585b; 180 | width: 74%; 181 | padding: 10px; 182 | border: 0px; 183 | } 184 | 185 | // Input for public spreadsheet URL to generate quiz 186 | #url { 187 | color: #ffffff; 188 | background-color: #58585b; 189 | width: 200px; 190 | padding: 2px; 191 | border: 0px; 192 | } -------------------------------------------------------------------------------- /source/javascripts/getdata.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | var key, pub, quizType; 3 | 4 | // initialize tabletop library 5 | function init() { 6 | Tabletop.init( { key: url, 7 | callback: readData, 8 | simpleSheet: true } ); 9 | } 10 | 11 | function readData(data, tabletop) { 12 | input = []; 13 | for ( var i = 0; i < data.length; i++ ) { 14 | input[i] = findUrlinObject( data[i] ); 15 | } 16 | console.log(input); 17 | embed(input); 18 | } 19 | 20 | function findUrlinObject ( data ) { 21 | $.each( data, function( key, value ){ 22 | if ( key == 'correct' || key == 'incorrect' || key == 'text') { 23 | data[key] = converttoHex( data[key] ); 24 | } 25 | } ); 26 | return data; 27 | } 28 | 29 | function converttoHex ( string ) { 30 | var hex, i; 31 | var result = ""; 32 | for ( i = 0; i < string.length; i++ ) { 33 | hex = string.charCodeAt( i ).toString( 16 ); 34 | result += ( "000" + hex ).slice( -4 ); 35 | } 36 | return result; 37 | } 38 | 39 | function addJS() { 40 | quizType = $('input[name="quiz-type"]:checked').val(); 41 | if (quizType == 'quiz') { 42 | $('body').append(''); 77 | pubStylesheet = "http://assets.sbnation.com.s3.amazonaws.com/features/quiz-generator/quiz-" + pub + ".css"; 78 | // pubStylesheet = "/stylesheets/quiz-" + pub + ".css"; 79 | } 80 | 81 | function embed(input) { 82 | $("#embedcode").html("<div class='quiz-container'><script type='text/javascript'>window.jQuery || document.write(\"<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'><\/script>\");</script><script type='text/javascript'>var input = " + JSON.stringify(input) + "; var pubStylesheet = '" + pubStylesheet + "'; var pub = '" + pub + "'; </script><script src='http://assets.sbnation.com.s3.amazonaws.com/features/quiz-generator/" + quizType + ".js'></script>"); 83 | // $("#embedcode").html("<div class='quiz-container'><script type='text/javascript'>window.jQuery || document.write('<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'><\/script>');</script><script type='text/javascript'>var input = " + JSON.stringify(input) + "; var pubStylesheet = '" + pubStylesheet + "';</script><script src='/javascripts/" + quizType + ".js'></script>"); 84 | addJS(); 85 | } 86 | 87 | function buildquiz(){ 88 | url = $('#url').val(); 89 | init(); 90 | getStylesheet(); 91 | } 92 | 93 | function buildflowchart() { 94 | url = $('#url').val(); 95 | init(); 96 | getStylesheet(); 97 | } 98 | 99 | $(document).ready(function() { 100 | $('input:radio[name=quiz-type]').click(function() { 101 | quizType = $('input:radio[name=quiz-type]:checked').val(); 102 | changeTemplate(); 103 | }); 104 | 105 | $('#build').on('click', function(){ 106 | if (quizType != undefined) { 107 | submitquiz(); 108 | } 109 | else { 110 | alert("Please choose a quiz type at the top of the page!"); 111 | } 112 | }) 113 | }) 114 | })(jQuery); -------------------------------------------------------------------------------- /source/demo.html.erb: -------------------------------------------------------------------------------- 1 |Correct!
" + input[currentQuestion].correct + "
"); 86 | 87 | } else { 88 | trackEvent( 89 | 'q' + qnumber + '-answered-incorrectly', 90 | 'Q' + qnumber + ' answered incorrectly'); 91 | $(".answer").html("Sorry!
" + input[currentQuestion].incorrect + " The correct answer is " + input[currentQuestion].answer + ".
"); 92 | } 93 | if (currentQuestion != (input.length-1)) { 94 | $(".answer").append(""); 95 | $('.next').on('click', nextQuestion); 96 | } else { 97 | $(".answer").append(""); 98 | $('.check-score').on('click', finalScore); 99 | } 100 | } 101 | } 102 | 103 | // increment question count and built new question and answers 104 | var nextQuestion = function () { 105 | trackEvent( 106 | 'q' + qnumber + '-next', 107 | 'Q' + qnumber + ' clicked to next question'); 108 | currentQuestion++; 109 | buildQuiz(input); 110 | } 111 | 112 | function trackEvent(action, label) { 113 | if( typeof(ga) != 'undefined' ) { 114 | ga('send', 'event', 'quiz', action, label); 115 | } else if (typeof(_gaq) != 'undefined' ){ 116 | _gaq.push($.merge(['_trackEvent', 'quiz'], arguments)); 117 | } 118 | } 119 | 120 | // display final score card and social media sharing 121 | var link = document.URL 122 | var finalScore = function () { 123 | trackEvent( 124 | 'scored-' + score + '-of-' + input.length, 125 | 'Scored ' + score + ' of ' + input.length); 126 | trackEvent('completed', 'Quiz completed'); 127 | switch (pub) { 128 | case 'vox': 129 | account = voxdotcom; 130 | break; 131 | case 'sbnation': 132 | account = sbnation; 133 | break; 134 | case 'verge': 135 | account = theverge; 136 | break; 137 | case 'polygon': 138 | account = polygon; 139 | break; 140 | case 'eater': 141 | account = eater; 142 | break; 143 | case 'racked': 144 | account = racked; 145 | break; 146 | default: 147 | account = 'voxproduct'; 148 | } 149 | 150 | $(".quiz-container") 151 | .html("You correctly answered
" + score + " out of " + input.length + "
Challenge your friends!
Correct!
" + input[currentQuestion].correct + "
"); 88 | 89 | } else { 90 | trackEvent( 91 | 'q' + qnumber + '-answered-incorrectly', 92 | 'Q' + qnumber + ' answered incorrectly'); 93 | $(".answer").html("Sorry!
" + input[currentQuestion].incorrect + " The correct answer is " + input[currentQuestion].answer + ".
"); 94 | } 95 | if (currentQuestion != (input.length-1)) { 96 | $(".answer").append(""); 97 | $('.next').on('click', nextQuestion); 98 | } else { 99 | $(".answer").append(""); 100 | $('.check-score').on('click', finalScore); 101 | } 102 | } 103 | } 104 | 105 | // increment question count and built new question and answers 106 | var nextQuestion = function () { 107 | trackEvent( 108 | 'q' + qnumber + '-next', 109 | 'Q' + qnumber + ' clicked to next question'); 110 | currentQuestion++; 111 | buildQuiz(input); 112 | } 113 | 114 | function trackEvent(action, label) { 115 | if( typeof(ga) != 'undefined' ) { 116 | ga('send', 'event', 'quiz', action, label); 117 | } else if (typeof(_gaq) != 'undefined' ){ 118 | _gaq.push($.merge(['_trackEvent', 'quiz'], arguments)); 119 | } 120 | } 121 | 122 | // display final score card and social media sharing 123 | var link = document.URL 124 | var finalScore = function () { 125 | trackEvent( 126 | 'scored-' + score + '-of-' + input.length, 127 | 'Scored ' + score + ' of ' + input.length); 128 | trackEvent('completed', 'Quiz completed'); 129 | switch (pub) { 130 | case 'vox': 131 | account = voxdotcom; 132 | break; 133 | case 'sbnation': 134 | account = sbnation; 135 | break; 136 | case 'verge': 137 | account = theverge; 138 | break; 139 | case 'polygon': 140 | account = polygon; 141 | break; 142 | case 'eater': 143 | account = eater; 144 | break; 145 | case 'racked': 146 | account = racked; 147 | break; 148 | default: 149 | account = 'voxproduct'; 150 | } 151 | 152 | $(".quiz-container") 153 | .html("You correctly answered
" + score + " out of " + input.length + "
Challenge your friends!
' + input[lastRow].text + '
| t |