Parent Directory
|
Revision Log
|
Revision Graph
the report pager was showing extra pages that weren't needed because it was counting all the keys in the DB instead of the keys that were actually used when people hit the site
| 1 | <?php |
| 2 | // $Id$ |
| 3 | |
| 4 | /** |
| 5 | * @file |
| 6 | * Distribution method for the Digital Propensity Index Questionanire |
| 7 | * and the instructional intervention for David Kent Norman's dissertation |
| 8 | * |
| 9 | * @author David Kent Norman |
| 10 | * @link http://deekayen.net |
| 11 | * @link http://dpistudy.com |
| 12 | * @copyright Copyright 2008 David Kent Norman |
| 13 | */ |
| 14 | |
| 15 | define('DPISTUDY_ALT_IRB_URL', 'http://education.ucf.edu/insttech/'); |
| 16 | define('DPISTUDY_NUM_QUESTIONS', 6); |
| 17 | |
| 18 | /** |
| 19 | * Implementation of hook_perm(). |
| 20 | * |
| 21 | * @return array |
| 22 | */ |
| 23 | function dpistudy_perm() { |
| 24 | return array('access dpistudy'); |
| 25 | } |
| 26 | |
| 27 | /** |
| 28 | * Implementation of hook_init(). |
| 29 | * |
| 30 | * Adds the timer javascript to the output and start the timer. |
| 31 | */ |
| 32 | function dpistudy_init() { |
| 33 | if (arg(0) != 'admin') { |
| 34 | _dpistudy_js_timer(); |
| 35 | _dpistudy_js_timer_start(); |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | /** |
| 40 | * Implementation of hook_menu(). |
| 41 | * |
| 42 | * @return array |
| 43 | */ |
| 44 | function dpistudy_menu() { |
| 45 | $items = array(); |
| 46 | |
| 47 | $items['dpistudy'] = array( |
| 48 | 'page callback' => 'dpistudy_hub', |
| 49 | 'page arguments' => array(), |
| 50 | 'access callback' => 'user_access', |
| 51 | 'access arguments' => array('access dpistudy'), |
| 52 | 'type' => MENU_CALLBACK, |
| 53 | 'title' => 'Get your Digital Propensity Index score!', |
| 54 | 'title callback' => 't', |
| 55 | 'title arguments' => array() |
| 56 | ); |
| 57 | $items['dpistudy/dpi'] = array( |
| 58 | 'page callback' => 'drupal_get_form', |
| 59 | 'page arguments' => array('dpistudy_dpi_questionnaire_form'), |
| 60 | 'access callback' => 'user_access', |
| 61 | 'access arguments' => array('access dpistudy'), |
| 62 | 'title' => 'Digital Propensity Index Questionnaire', |
| 63 | 'title callback' => 't', |
| 64 | 'title arguments' => array(), |
| 65 | 'type' => MENU_CALLBACK |
| 66 | ); |
| 67 | $items['dpistudy/instruction'] = array( |
| 68 | 'page callback' => 'drupal_get_form', |
| 69 | 'page arguments' => array('dpistudy_instruction_form'), |
| 70 | 'access callback' => 'user_access', |
| 71 | 'access arguments' => array('access dpistudy'), |
| 72 | 'title' => 'Just @num more!', // not ideal, but this or arguments have to be passed for the callback to be executed |
| 73 | 'title callback' => 'dpistudy_instruction_title', |
| 74 | 'type' => MENU_CALLBACK |
| 75 | ); |
| 76 | $items['dpistudy/score'] = array( |
| 77 | 'page callback' => 'dpistudy_score', |
| 78 | 'page arguments' => array(), |
| 79 | 'access callback' => 'user_access', |
| 80 | 'access arguments' => array('access dpistudy'), |
| 81 | 'title' => 'Your Digital Propensity Index score!', |
| 82 | 'title callback' => 't', |
| 83 | 'title arguments' => array(), |
| 84 | 'type' => MENU_CALLBACK |
| 85 | ); |
| 86 | $items['admin/settings/dpistudy'] = array( |
| 87 | 'page callback' => 'drupal_get_form', |
| 88 | 'page arguments' => array('dpistudy_admin_settings'), |
| 89 | 'access callback' => 'user_access', |
| 90 | 'access arguments' => array('administer site configuration'), |
| 91 | 'description' => 'Toggle features of the DPI questionnaire.', |
| 92 | 'title' => 'DPI Study', |
| 93 | 'title callback' => 't', |
| 94 | 'title arguments' => array(), |
| 95 | 'type' => MENU_NORMAL_ITEM |
| 96 | ); |
| 97 | $items['admin/settings/dpistudy/settings'] = array( |
| 98 | 'page callback' => 'drupal_get_form', |
| 99 | 'page arguments' => array('dpistudy_admin_settings'), |
| 100 | 'access callback' => 'user_access', |
| 101 | 'access arguments' => array('administer site configuration'), |
| 102 | 'title' => 'Settings', |
| 103 | 'title callback' => 't', |
| 104 | 'title arguments' => array(), |
| 105 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 106 | 'weight' => 0 |
| 107 | ); |
| 108 | $items['admin/settings/dpistudy/keys'] = array( |
| 109 | 'page callback' => 'dpistudy_admin_settings_invite_keys', |
| 110 | 'page arguments' => array(), |
| 111 | 'access callback' => 'user_access', |
| 112 | 'access arguments' => array('administer site configuration'), |
| 113 | 'title' => 'Invite Keys', |
| 114 | 'title callback' => 't', |
| 115 | 'title arguments' => array(), |
| 116 | 'type' => MENU_LOCAL_TASK, |
| 117 | 'weight' => 3 |
| 118 | ); |
| 119 | $items['admin/settings/dpistudy/keys/delete'] = array( |
| 120 | 'page callback' => 'dpistudy_admin_settings_invite_keys_delete', |
| 121 | 'page arguments' => array(5), |
| 122 | 'access callback' => 'user_access', |
| 123 | 'access arguments' => array('administer site configuration'), |
| 124 | 'title' => 'Delete a key', |
| 125 | 'title callback' => 't', |
| 126 | 'title arguments' => array(), |
| 127 | 'type' => MENU_LOCAL_TASK, |
| 128 | 'weight' => 3 |
| 129 | ); |
| 130 | $items['admin/settings/dpistudy/questions'] = array( |
| 131 | 'page callback' => 'dpistudy_admin_settings_list_questions', |
| 132 | 'page arguments' => array(), |
| 133 | 'access callback' => 'user_access', |
| 134 | 'access arguments' => array('administer site configuration'), |
| 135 | 'description' => 'Manage questions on the questionnaire.', |
| 136 | 'title' => 'Questionnaire', |
| 137 | 'title callback' => 't', |
| 138 | 'title arguments' => array(), |
| 139 | 'type' => MENU_LOCAL_TASK, |
| 140 | 'weight' => 5 |
| 141 | ); |
| 142 | $items['admin/settings/dpistudy/questions/list'] = array( |
| 143 | 'page callback' => 'dpistudy_admin_settings_list_questions', |
| 144 | 'page arguments' => array(), |
| 145 | 'access callback' => 'user_access', |
| 146 | 'access arguments' => array('administer site configuration'), |
| 147 | 'description' => 'Manage questions on the questionnaire.', |
| 148 | 'title' => 'List questions', |
| 149 | 'title callback' => 't', |
| 150 | 'title arguments' => array(), |
| 151 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 152 | 'weight' => 0 |
| 153 | ); |
| 154 | $items['admin/settings/dpistudy/questions/add'] = array( |
| 155 | 'page callback' => 'drupal_get_form', |
| 156 | 'page arguments' => array('dpistudy_admin_settings_add_question_form'), |
| 157 | 'access callback' => 'user_access', |
| 158 | 'access arguments' => array('administer site configuration'), |
| 159 | 'description' => 'Adds a question to the questionnaire.', |
| 160 | 'title' => 'Add question', |
| 161 | 'title callback' => 't', |
| 162 | 'title arguments' => array(), |
| 163 | 'type' => MENU_LOCAL_TASK, |
| 164 | 'weight' => 5 |
| 165 | ); |
| 166 | $items['admin/reports/dpistudy'] = array( |
| 167 | 'page callback' => 'dpistudy_report', |
| 168 | 'page arguments' => array(), |
| 169 | 'access callback' => 'user_access', |
| 170 | 'access arguments' => array('administer site configuration'), |
| 171 | 'description' => 'View the breakdown of responses for each invite key and copy quick links for keyed visitors.', |
| 172 | 'title' => 'DPI Study', |
| 173 | 'title callback' => 't', |
| 174 | 'title arguments' => array(), |
| 175 | 'type' => MENU_NORMAL_ITEM |
| 176 | ); |
| 177 | $items['admin/reports/dpistudy/visits'] = array( |
| 178 | 'page callback' => 'dpistudy_report', |
| 179 | 'page arguments' => array(), |
| 180 | 'access callback' => 'user_access', |
| 181 | 'access arguments' => array('administer site configuration'), |
| 182 | 'title' => 'Visits', |
| 183 | 'title callback' => 't', |
| 184 | 'title arguments' => array(), |
| 185 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 186 | 'weight' => 0 |
| 187 | ); |
| 188 | $items['admin/reports/dpistudy/export'] = array( |
| 189 | 'page callback' => 'dpistudy_csv_export', |
| 190 | 'page arguments' => array(), |
| 191 | 'access callback' => 'user_access', |
| 192 | 'access arguments' => array('administer site configuration'), |
| 193 | 'description' => 'Export survey results to a spreadsheet.', |
| 194 | 'title' => 'Export', |
| 195 | 'title callback' => 't', |
| 196 | 'title arguments' => array(), |
| 197 | 'type' => MENU_LOCAL_TASK, |
| 198 | 'weight' => 10 |
| 199 | ); |
| 200 | return $items; |
| 201 | } |
| 202 | |
| 203 | /** |
| 204 | * Enter description here... |
| 205 | * |
| 206 | * @param string $title |
| 207 | */ |
| 208 | function dpistudy_instruction_title($title) { |
| 209 | if ($_SESSION['instruction_number'] == 6) { |
| 210 | return t('Last one!'); |
| 211 | } |
| 212 | else { |
| 213 | return t($title, array('@num' => (empty($_SESSION['instruction_number']) ? DPISTUDY_NUM_QUESTIONS - 1 : DPISTUDY_NUM_QUESTIONS - $_SESSION['instruction_number']))); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * @return array |
| 219 | */ |
| 220 | function dpistudy_admin_settings() { |
| 221 | $form = array(); |
| 222 | $form['dpistudy_add_form_num_questions'] = array( |
| 223 | '#type' => 'textfield', |
| 224 | '#title' => t('Number of answers on add question form'), |
| 225 | '#size' => 4, |
| 226 | '#default_value' => variable_get('dpistudy_add_form_num_questions', 5) |
| 227 | ); |
| 228 | $form['consent'] = array( |
| 229 | '#type' => 'fieldset', |
| 230 | '#title' => t('Consent form'), |
| 231 | '#collapsible' => true, |
| 232 | '#collapsed' => true |
| 233 | ); |
| 234 | $form['consent']['dpistudy_irb_consent_active'] = array( |
| 235 | '#type' => 'radios', |
| 236 | '#options' => array('disabled', 'enabled'), |
| 237 | '#title' => t('Toggle IRB consent screen'), |
| 238 | '#default_value' => variable_get('dpistudy_irb_consent_active', 0), |
| 239 | '#description' => t('Enabling the IRB form will require people to view .') |
| 240 | ); |
| 241 | $form['consent']['dpistudy_irb_text'] = array( |
| 242 | '#type' => 'textarea', |
| 243 | '#rows' => 25, |
| 244 | '#title' => t('Text to output on the IRB consent form.'), |
| 245 | '#default_value' => variable_get('dpistudy_irb_text', ''), |
| 246 | '#description' => t('HTML is allowed.') |
| 247 | ); |
| 248 | $form['dpistudy_score_screen'] = array( |
| 249 | '#type' => 'textarea', |
| 250 | '#rows' => 10, |
| 251 | '#title' => t('Score screen text'), |
| 252 | '#description' => t('Text to output on the final screen where the DPI score is presented. Use @score as the placeholder for the numerical score. HTML is allowed.'), |
| 253 | '#default_value' => variable_get('dpistudy_score_screen', ''), |
| 254 | ); |
| 255 | $form['dpistudy_alt_irb_url'] = array( |
| 256 | '#type' => 'textfield', |
| 257 | '#title' => t('Alternate IRB URL'), |
| 258 | '#default_value' => variable_get('dpistudy_alt_irb_url', DPISTUDY_ALT_IRB_URL), |
| 259 | '#description' => t('Alternate URL to link users to under the "I Consent" button on the IRB consent form.') |
| 260 | ); |
| 261 | return system_settings_form($form); |
| 262 | } |
| 263 | |
| 264 | /** |
| 265 | * Handles new key adding and displays current invite keys |
| 266 | * |
| 267 | * @return string |
| 268 | */ |
| 269 | function dpistudy_admin_settings_invite_keys() { |
| 270 | $headers = array( |
| 271 | array('data' => t('Invite Key'), 'field' => 'invite_key', 'sort' => 'asc'), |
| 272 | array('data' => t('Notes'), 'field' => 'notes'), |
| 273 | array('data' => t('Action')) |
| 274 | ); |
| 275 | |
| 276 | $sql = 'SELECT invite_key, notes FROM {dpistudy_keys}'; |
| 277 | $sql .= tablesort_sql($headers); |
| 278 | |
| 279 | $count = 'SELECT COUNT(*) FROM {dpistudy_keys}'; |
| 280 | $result = pager_query($sql, 15, 0, $count); |
| 281 | |
| 282 | while ($key = db_fetch_object($result)) { |
| 283 | $rows[] = array($key->invite_key, $key->notes, l(t('delete'), 'admin/settings/dpistudy/keys/delete/' . $key->invite_key)); |
| 284 | } |
| 285 | |
| 286 | $pager = theme('pager', NULL, 15); |
| 287 | |
| 288 | if (!empty($pager)) { |
| 289 | $rows[] = array(array('data' => $pager, 'colspan' => 3)); |
| 290 | } |
| 291 | |
| 292 | $output = theme('table', $headers, $rows); |
| 293 | return $output . drupal_get_form('dpistudy_admin_settings_invite_keys_form'); |
| 294 | } |
| 295 | |
| 296 | /** |
| 297 | * Handles new key removing current invite keys |
| 298 | * |
| 299 | * @return string |
| 300 | */ |
| 301 | function dpistudy_admin_settings_invite_keys_delete($key) { |
| 302 | db_query("DELETE FROM {dpistudy_keys} WHERE invite_key = '%s'", $key); |
| 303 | drupal_set_message(t('!key deleted.', array('!key' => $key)), 'status'); |
| 304 | drupal_goto('admin/settings/dpistudy/keys'); |
| 305 | } |
| 306 | |
| 307 | /** |
| 308 | * @return array |
| 309 | */ |
| 310 | function dpistudy_admin_settings_invite_keys_form() { |
| 311 | $form = array(); |
| 312 | $form['add_key'] = array( |
| 313 | '#type' => 'fieldset', |
| 314 | '#title' => t('Add new invite key'), |
| 315 | '#collapsible' => true, |
| 316 | '#collapsed' => true |
| 317 | ); |
| 318 | $form['add_key']['dpistudy_new_invite_key'] = array( |
| 319 | '#type' => 'textfield', |
| 320 | '#title' => t('New invite key'), |
| 321 | '#size' => 4, |
| 322 | '#default_value' => '', |
| 323 | '#required' => true, |
| 324 | '#maxlength' => 50, |
| 325 | '#description' => t('Entry can be alphanumeric.') |
| 326 | ); |
| 327 | $form['add_key']['dpistudy_new_invite_key_notes'] = array( |
| 328 | '#type' => 'textfield', |
| 329 | '#title' => t('Key notes'), |
| 330 | '#description' => t('Notes on the audience to be associated with the key.'), |
| 331 | '#maxlength' => 255, |
| 332 | '#default_value' => '' |
| 333 | ); |
| 334 | $form['add_key']['submit'] = array( |
| 335 | '#type' => 'submit', |
| 336 | '#value' => t('Add key') |
| 337 | ); |
| 338 | return $form; |
| 339 | } |
| 340 | |
| 341 | /** |
| 342 | * Validate the form submission from dpistudy_admin_settings_invite_keys_form() |
| 343 | * |
| 344 | * @param array $form |
| 345 | * @param array $form_state |
| 346 | */ |
| 347 | function dpistudy_admin_settings_invite_keys_form_validate($form, &$form_state) { |
| 348 | if ($form_state['values']['dpistudy_new_invite_key'] == '') { |
| 349 | form_set_error('dpistudy_new_invite_key', t('You must add some text to the key value.')); |
| 350 | } |
| 351 | $existing = db_result(db_query("SELECT COUNT(*) FROM {dpistudy_keys} WHERE invite_key = '%s'", $form_state['values']['dpistudy_new_invite_key'])); |
| 352 | if ($existing > 0) { |
| 353 | form_set_error('dpistudy_new_invite_key', t('"!key" is already a key! You must delete the old one first.', array('!key' => $form_state['values']['dpistudy_new_invite_key']))); |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | /** |
| 358 | * Process the form submission from dpistudy_admin_settings_invite_keys_form() |
| 359 | * |
| 360 | * @param array $form |
| 361 | * @param array $form_state |
| 362 | */ |
| 363 | function dpistudy_admin_settings_invite_keys_form_submit($form, &$form_state) { |
| 364 | db_query("INSERT INTO {dpistudy_keys} (invite_key, notes) VALUES ('%s', '%s')", $form_state['values']['dpistudy_new_invite_key'], $form_state['values']['dpistudy_new_invite_key_notes']); |
| 365 | drupal_set_message(t('Invite key "!key" added', array('!key' => $form_state['values']['dpistudy_new_invite_key']))); |
| 366 | cache_clear_all('dpistudy-', 'cache', TRUE); |
| 367 | } |
| 368 | |
| 369 | /** |
| 370 | * Lists questions on the questionnaire and allows weight adjustment |
| 371 | * active/deactivate |
| 372 | * |
| 373 | * @return string |
| 374 | */ |
| 375 | function dpistudy_admin_settings_list_questions() { |
| 376 | $headers = array( |
| 377 | array('data' => t('Weight'), 'field' => 'weight'), |
| 378 | array('data' => t('Title'), 'field' => 'title') |
| 379 | ); |
| 380 | |
| 381 | $sql = 'SELECT pkid, weight, title FROM {dpistudy_questions} GROUP BY weight, title'; |
| 382 | $sql .= tablesort_sql($headers); |
| 383 | |
| 384 | $count = 'SELECT COUNT(*) FROM {dpistudy_questions}'; |
| 385 | $result = pager_query($sql, 50, 0, $count); |
| 386 | |
| 387 | while ($question = db_fetch_object($result)) { |
| 388 | $weight = $question->weight; |
| 389 | // $weight .= drupal_render(array(['my_elements'][$delta]['weight']['#attributes']['class'] = 'my-elements-weight')); |
| 390 | |
| 391 | $title = l($question->title, "admin/settings/dpistudy/question/view/{$question->pkid}", array('attributes' => array('title' => t('View detailed question information')))); |
| 392 | $rows[] = array( |
| 393 | 'data' => array($weight, $title), |
| 394 | 'class' => 'draggable' |
| 395 | ); |
| 396 | } |
| 397 | |
| 398 | $pager = theme('pager', NULL, 50); |
| 399 | |
| 400 | if (!empty($pager)) { |
| 401 | $rows[] = array(array('data' => $pager, 'colspan' => 2)); |
| 402 | } |
| 403 | |
| 404 | $output = theme('table', $headers, $rows, array('id' => 'dpistudy-questions')); |
| 405 | return $output; |
| 406 | } |
| 407 | |
| 408 | /** |
| 409 | * Form for modifying the content of the questionnaire |
| 410 | * |
| 411 | * @param integer $pkid |
| 412 | * @param integer $weight |
| 413 | * @return array |
| 414 | */ |
| 415 | function dpistudy_admin_settings_list_questions_weight($pkid, $weight = 0) { |
| 416 | $form = array(); |
| 417 | $form["question_{$pkid}_weight"] = array( |
| 418 | '#type' => 'select', |
| 419 | '#title' => '', |
| 420 | '#default_value' => $weight, |
| 421 | '#options' => drupal_map_assoc(range(-50, 50)) |
| 422 | ); |
| 423 | return $form; |
| 424 | } |
| 425 | |
| 426 | /** |
| 427 | * Form for modifying the content of the questionnaire |
| 428 | * |
| 429 | * @return array |
| 430 | */ |
| 431 | function dpistudy_admin_settings_list_questions_form() { |
| 432 | $form = array(); |
| 433 | $form['submit'] = array( |
| 434 | '#type' => 'submit', |
| 435 | '#value' => t('Update questions') |
| 436 | ); |
| 437 | return $form; |
| 438 | } |
| 439 | |
| 440 | /** |
| 441 | * Form to add a question to the questionnaire. |
| 442 | * Defaults to 10 question answers. |
| 443 | * |
| 444 | * @todo de-hardcode the question type |
| 445 | * @return array |
| 446 | */ |
| 447 | function dpistudy_admin_settings_add_question_form() { |
| 448 | $form = array(); |
| 449 | $form['question_type'] = array( |
| 450 | '#type' => 'radios', |
| 451 | '#options' => array('Radio buttons', 'Checkbox'), |
| 452 | '#title' => t('Question type'), |
| 453 | '#description' => t('Select radio buttons for a single response per question or checkbox for multiple answers to the question. Currently, only radio buttons are supported.'), |
| 454 | '#weight' => 0, |
| 455 | // currently only radio is supported |
| 456 | '#default_value' => 0, |
| 457 | '#disabled' => true |
| 458 | ); |
| 459 | $form['question_title'] = array( |
| 460 | '#type' => 'textfield', |
| 461 | '#title' => t('Question title'), |
| 462 | '#description' => t('Note: A colon is automatically appended to the question text.'), |
| 463 | '#weight' => 1, |
| 464 | '#maxlength' => 250 |
| 465 | ); |
| 466 | $form['answers'] = array( |
| 467 | '#type' => 'fieldset', |
| 468 | '#title' => t('Answers'), |
| 469 | '#collapsible' => true, |
| 470 | '#collapsed' => false, |
| 471 | '#weight' => 2 |
| 472 | ); |
| 473 | for ($i=1, $j = variable_get('dpistudy_add_form_num_questions', 5); $i <= $j; $i++) { |
| 474 | $form['answers']['answer'][$i] = array( |
| 475 | '#type' => 'fieldset', |
| 476 | '#collapsible' => false, |
| 477 | '#collapsed' => false |
| 478 | ); |
| 479 | $form['answers']['answer'][$i][$i] = array( |
| 480 | '#type' => 'textfield', |
| 481 | '#title' => t('Answer %i', array('%i' => $i)), |
| 482 | '#weight' => $i, |
| 483 | '#maxlength' => 250 |
| 484 | ); |
| 485 | $form['answers']['answer'][$i]["{$i}_weight"] = array( |
| 486 | '#type' => 'select', |
| 487 | '#title' => t('Weight'), |
| 488 | '#default_value' => $i, |
| 489 | '#options' => drupal_map_assoc(range(-15, 15)) |
| 490 | ); |
| 491 | } |
| 492 | $form['question_weight'] = array( |
| 493 | '#type' => 'textfield', |
| 494 | '#size' => 4, |
| 495 | '#title' => t('Question weight'), |
| 496 | '#default_value' => '0', // text value will convert to integer in database |
| 497 | '#description' => t('Integer to dictate the order of the questions in the questionnaire. Questions with higher weight will be lower in the question order. Questions with the same weight will order alphabetically. For example, question number 20 would likely have a weight of 20.'), |
| 498 | '#weight' => $i |
| 499 | ); |
| 500 | $form['submit'] = array( |
| 501 | '#type' => 'submit', |
| 502 | '#value' => t('Add question'), |
| 503 | '#weight' => $i + 1 |
| 504 | ); |
| 505 | return $form; |
| 506 | } |
| 507 | |
| 508 | /** |
| 509 | * Process the form submission from dpistudy_admin_settings_add_question_form() |
| 510 | * |
| 511 | * @param array $form |
| 512 | * @param array $form_status |
| 513 | */ |
| 514 | function dpistudy_admin_settings_add_question_form_submit($form, &$form_status) { |
| 515 | $answers = array(); |
| 516 | while (list($key, $value) = each($form_status['values'])) { |
| 517 | if (is_integer($key)) { |
| 518 | $answers[$key] = $value; |
| 519 | } |
| 520 | } |
| 521 | ksort($answers); |
| 522 | db_query("INSERT INTO {dpistudy_questions} (weight, title) VALUES (%d, '%s')", $form_status['values']['question_weight'], $form_status['values']['question_title']); |
| 523 | $id = db_last_insert_id('dpistudy_questions', 'pkid'); |
| 524 | while (list($key, $value) = each($answers)) { |
| 525 | // todo - format like this: |
| 526 | // INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9); |
| 527 | db_query("INSERT INTO {dpistudy_answers} (parent, weight, answer) VALUES (%d, %d, '%s')", $id, $key . '_weight', $value); |
| 528 | } |
| 529 | drupal_set_message(t('Question "%title" added', array('%title' => $form_status['values']['question_title']))); |
| 530 | cache_clear_all('dpistudy-', 'cache', TRUE); |
| 531 | } |
| 532 | |
| 533 | /** |
| 534 | * Sends the survey results in CSV format |
| 535 | * Requires PHP5 |
| 536 | * |
| 537 | */ |
| 538 | function dpistudy_csv_export() { |
| 539 | // http://support.microsoft.com/kb/318756 says not to add charset |
| 540 | // but http://api.drupal.org/api/5/function/drupal_set_header says the charset prevents XSS |
| 541 | drupal_set_header('Content-type: application/vnd.ms-excel; charset=utf-8'); |
| 542 | drupal_set_header('Content-Disposition: attachment; filename=dpistudy_' . date('YmdHis') . '.csv'); |
| 543 | drupal_set_header('Expires: 0'); |
| 544 | drupal_set_header('Cache-Control: must-revalidate, post-check=0,pre-check=0'); |
| 545 | drupal_set_header('Pragma: public'); |
| 546 | |
| 547 | $out = fopen('php://output', 'w'); |
| 548 | |
| 549 | // set column headings for the CSV file |
| 550 | $headers = array(); |
| 551 | $headers[] = 'sessid'; |
| 552 | $headers[] = 'invite_key'; |
| 553 | $headers[] = 'key_notes'; |
| 554 | $headers[] = 'agent'; |
| 555 | $headers[] = 'referer'; |
| 556 | $headers[] = 'irb_php'; |
| 557 | $headers[] = 'irb_http'; |
| 558 | $headers[] = 'irb_js'; |
| 559 | for ($i=1; $i<47; $i++) { |
| 560 | $headers[] = "q$i"; |
| 561 | } |
| 562 | $headers[] = 'dpi_php'; |
| 563 | $headers[] = 'dpi_http'; |
| 564 | $headers[] = 'dpi_js'; |
| 565 | for ($i=100; $i<106; $i++) { |
| 566 | $headers[] = "q$i"; |
| 567 | $headers[] = "php_q$i"; |
| 568 | $headers[] = "http_q$i"; |
| 569 | $headers[] = "js_q$i"; |
| 570 | } |
| 571 | fputcsv($out, $headers); |
| 572 | unset($headers); |
| 573 | |
| 574 | // pre-populate default participant as non-response |
| 575 | // for every question |
| 576 | $populated_answer = array(); |
| 577 | $populated_answer['invite_key'] = ''; |
| 578 | $populated_answer['key_notes'] = ''; |
| 579 | $populated_answer['agent'] = ''; |
| 580 | $populated_answer['referer'] = ''; |
| 581 | $populated_answer['irb_php'] = ''; |
| 582 | $populated_answer['irb_http'] = ''; |
| 583 | $populated_answer['irb_js'] = ''; |
| 584 | for ($i=1; $i<47; $i++) { |
| 585 | // 9 will be set as a missing value in SPSS |
| 586 | $populated_answer["q$i"] = 9; |
| 587 | } |
| 588 | $populated_answer['dpi_php'] = 0; |
| 589 | $populated_answer['dpi_http'] = 0; |
| 590 | $populated_answer['dpi_js'] = 0; |
| 591 | for ($i=100; $i<106; $i++) { |
| 592 | $populated_answer["q$i"] = 6; |
| 593 | $populated_answer["php_q$i"] = 0; |
| 594 | $populated_answer["http_q$i"] = 0; |
| 595 | $populated_answer["js_q$i"] = 0; |
| 596 | } |
| 597 | unset($i); |
| 598 | |
| 599 | /** |
| 600 | * Replace non-response values with actual responses. |
| 601 | * Non-response values will stay. Using this method |
| 602 | * because the database doesn't store non-responses, |
| 603 | * just actual values. If the participant never |
| 604 | * submits their responses, there won't be a session |
| 605 | * id value to fire the fputcsv() that would represent |
| 606 | * a participant. |
| 607 | */ |
| 608 | |
| 609 | $answer = array(); |
| 610 | |
| 611 | // just DPI questionnaire results |
| 612 | $result = db_query('SELECT r.sessid, l.invite_key, k.notes, l.agent, l.referer, l.irb_php_timer AS irb_php, l.irb_apache_timer AS irb_http, l.irb_js_timer AS irb_js, r.question, r.answer, r.php_timer, r.apache_timer, r.js_timer FROM {dpistudy_responses} AS r LEFT JOIN {dpistudy_login} AS l ON r.sessid = l.sessid LEFT JOIN {dpistudy_keys} AS k ON l.invite_key = k.invite_key WHERE r.question < 100 ORDER BY l.invite_key, r.sessid, r.question'); |
| 613 | while ($r = db_fetch_object($result)) { |
| 614 | // storing to an array like this could kill available |
| 615 | // RAM, so hopefully it won't get out of control |
| 616 | if (!isset($answer[$r->sessid])) { |
| 617 | $answer[$r->sessid] = $populated_answer; |
| 618 | } |
| 619 | $answer[$r->sessid]['invite_key'] = $r->invite_key; |
| 620 | $answer[$r->sessid]['key_notes'] = $r->notes; |
| 621 | $answer[$r->sessid]['agent'] = $r->agent; |
| 622 | $answer[$r->sessid]['referer'] = $r->referer; |
| 623 | $answer[$r->sessid]['irb_php'] = $r->irb_php; |
| 624 | $answer[$r->sessid]['irb_http'] = $r->irb_http; |
| 625 | $answer[$r->sessid]['irb_js'] = $r->irb_js; |
| 626 | $answer[$r->sessid]['dpi_php'] = $r->php_timer; |
| 627 | $answer[$r->sessid]['dpi_http'] = $r->apache_timer; |
| 628 | $answer[$r->sessid]['dpi_js'] = $r->js_timer; |
| 629 | $answer[$r->sessid]["q{$r->question}"] = $r->answer; |
| 630 | } |
| 631 | |
| 632 | // add on the instructional responses |
| 633 | $result = db_query('SELECT r.sessid, l.invite_key, k.notes, l.agent, l.referer, l.irb_php_timer AS irb_php, l.irb_apache_timer AS irb_http, l.irb_js_timer AS irb_js, r.question, r.answer, r.php_timer, r.apache_timer, r.js_timer FROM {dpistudy_responses} AS r LEFT JOIN {dpistudy_login} AS l ON r.sessid = l.sessid LEFT JOIN {dpistudy_keys} AS k ON l.invite_key = k.invite_key WHERE r.question > 99 ORDER BY l.invite_key, r.sessid, r.question'); |
| 634 | while ($r = db_fetch_object($result)) { |
| 635 | // storing to an array like this could kill available |
| 636 | // RAM, so hopefully it won't get out of control |
| 637 | if (!isset($answer[$r->sessid])) { |
| 638 | $answer[$r->sessid] = $populated_answer; |
| 639 | } |
| 640 | $answer[$r->sessid]['invite_key'] = $r->invite_key; |
| 641 | $answer[$r->sessid]['key_notes'] = $r->notes; |
| 642 | $answer[$r->sessid]['agent'] = $r->agent; |
| 643 | $answer[$r->sessid]['referer'] = $r->referer; |
| 644 | $answer[$r->sessid]['irb_php'] = $r->irb_php; |
| 645 | $answer[$r->sessid]['irb_http'] = $r->irb_http; |
| 646 | $answer[$r->sessid]['irb_js'] = $r->irb_js; |
| 647 | $answer[$r->sessid]["q{$r->question}"] = $r->answer; |
| 648 | $answer[$r->sessid]["php_q{$r->question}"] = $r->php_timer; |
| 649 | $answer[$r->sessid]["http_q{$r->question}"] = $r->apache_timer; |
| 650 | $answer[$r->sessid]["js_q{$r->question}"] = $r->js_timer; |
| 651 | } |
| 652 | while (list($sessid, $response) = each($answer)) { |
| 653 | fputcsv($out, array_merge(array($sessid), $response)); |
| 654 | unset($answer[$sessid]); |
| 655 | } |
| 656 | fclose($out); |
| 657 | } |
| 658 | |
| 659 | /** |
| 660 | * Breakout of how many people responded in each invite key. |
| 661 | */ |
| 662 | function dpistudy_report() { |
| 663 | $headers = array( |
| 664 | array('data' => t('Invite Key'), 'field' => 'invite_key', 'sort' => 'asc'), |
| 665 | array('data' => t('Visits')), |
| 666 | array('data' => t('Invite link')) |
| 667 | ); |
| 668 | |
| 669 | $sql = 'SELECT invite_key, COUNT(sessid) AS responses FROM {dpistudy_login} GROUP BY invite_key'; |
| 670 | $sql .= tablesort_sql($headers); |
| 671 | |
| 672 | $count = 'SELECT COUNT(DISTINCT(invite_key)) FROM {dpistudy_login}'; |
| 673 | $result = pager_query($sql, 15, 0, $count); |
| 674 | |
| 675 | while ($response = db_fetch_object($result)) { |
| 676 | // str_replace()ing # is kind of hacky, but passing '?key=' to url() translates |
| 677 | // the ? and = through drupal_urlencode() and no longer shows ? and = |
| 678 | // in the output, rather the translated urlencode equivalents |
| 679 | $rows[] = array($response->invite_key, $response->responses, l(str_replace('#', '', url('<front>', array('absolute' => true, 'fragment' => '?k=' . $response->invite_key))), '?k=' . $response->invite_key, array('absolute' => true))); |
| 680 | } |
| 681 | |
| 682 | $pager = theme('pager', NULL, 15); |
| 683 | |
| 684 | if (!empty($pager)) { |
| 685 | $rows[] = array(array('data' => $pager, 'colspan' => 3)); |
| 686 | } |
| 687 | |
| 688 | $output = theme('table', $headers, $rows); |
| 689 | return $output; |
| 690 | } |
| 691 | |
| 692 | /** |
| 693 | * Gateway function to control what is displayed. |
| 694 | * 1. IRB |
| 695 | * 2. DPI |
| 696 | * 3. Instruction |
| 697 | * |
| 698 | * This function uses $_SESSION as a checklist of things |
| 699 | * the user has completed. If nothing is set for the dpistudy |
| 700 | * array element, nothing has been completed. When IRB is set, it |
| 701 | * means the user has accepted the risks involved with the project |
| 702 | * and is ready to move on to the questionnaire. |
| 703 | * When $_SESSION['questionnaire'] is DPI, the user has submitted |
| 704 | * their DPI questionnaire and is ready for instruction, and so on. |
| 705 | * |
| 706 | * @return string |
| 707 | */ |
| 708 | function dpistudy_hub() { |
| 709 | if (empty($_SESSION['logged_in'])) { |
| 710 | if (isset($_REQUEST['k'])) { |
| 711 | db_query("INSERT INTO {dpistudy_login} (sessid, invite_key, agent, referer) VALUES ('%s', '%s', '%s', '%s')", session_id(), $_REQUEST['k'], $_SERVER['HTTP_USER_AGENT'], $_SERVER['HTTP_REFERER']); |
| 712 | } |
| 713 | else { |
| 714 | db_query("INSERT INTO {dpistudy_login} (sessid, agent, referer) VALUES ('%s', '%s', '%s')", session_id(), $_SERVER['HTTP_USER_AGENT'], $_SERVER['HTTP_REFERER']); |
| 715 | } |
| 716 | } |
| 717 | $_SESSION['logged_in'] = TRUE; |
| 718 | |
| 719 | if (variable_get('dpistudy_irb_consent_active', 0) && !isset($_SESSION['dpistudy']['irb_consent'])) { |
| 720 | return drupal_get_form('dpistudy_irb_form'); |
| 721 | } |
| 722 | else { |
| 723 | drupal_goto('dpistudy/dpi'); |
| 724 | } |
| 725 | } |
| 726 | |
| 727 | /** |
| 728 | * @return array |
| 729 | */ |
| 730 | function dpistudy_irb_form() { |
| 731 | $form = array(); |
| 732 | $form['irb_text'] = array( |
| 733 | '#value' => variable_get('dpistudy_irb_text', '') |
| 734 | ); |
| 735 | $form['microtime'] = array( |
| 736 | '#type' => 'hidden', |
| 737 | '#value' => microtime(true) |
| 738 | ); |
| 739 | $form['request_time'] = array( |
| 740 | '#type' => 'hidden', |
| 741 | '#value' => $_SERVER['REQUEST_TIME'] |
| 742 | ); |
| 743 | $form['js_timer'] = array( |
| 744 | '#type' => 'hidden' |
| 745 | ); |
| 746 | $form['submit'] = array( |
| 747 | '#type' => 'submit', |
| 748 | '#value' => t('I consent'), |
| 749 | '#weight' => 1, |
| 750 | '#suffix' => '<p class="alt_consent">' . l(t("I'm not sure. Take me somewhere else."), variable_get('disseration_alt_irb_url', DPISTUDY_ALT_IRB_URL)) . '</p>' |
| 751 | ); |
| 752 | $form['#attributes'] = array('name' => 'dpistudy'); |
| 753 | $form['#redirect'] = 'dpistudy/dpi'; |
| 754 | return $form; |
| 755 | } |
| 756 | |
| 757 | function dpistudy_irb_form_submit($form, &$form_status) { |
| 758 | $_SESSION['dpistudy']['irb_consent'] = true; |
| 759 | |
| 760 | $times = _dpistudy_calculate_times( |
| 761 | $form_status['clicked_button']['#post']['microtime'], |
| 762 | $form_status['clicked_button']['#post']['request_time'], |
| 763 | $form_status['values']['js_timer'] |
| 764 | ); |
| 765 | |
| 766 | db_query("UPDATE {dpistudy_login} SET irb_php_timer = '%f', irb_apache_timer = %d, irb_js_timer = %d WHERE sessid = '%s'", $times['microtime'], $times['http_header'], $times['javascript'], session_id()); |
| 767 | } |
| 768 | |
| 769 | /** |
| 770 | * Displays the DPI questionnaire. When the responses are submitted, it |
| 771 | * commits them to the database and forwards on to the instructional unit. |
| 772 | * |
| 773 | * @return array |
| 774 | */ |
| 775 | function dpistudy_dpi_questionnaire_form() { |
| 776 | $i = 1; |
| 777 | $form = array(); |
| 778 | $form['open_table'] = array( |
| 779 | '#type' => 'markup', |
| 780 | '#value' => '<table border="0" cellpadding="2" cellspacing="2" summary="">' |
| 781 | ); |
| 782 | |
| 783 | $questions = cache_get('dpistudy-questions'); |
| 784 | $questions = $questions->data; |
| 785 | if (empty($questions)) { |
| 786 | $questions = array(); |
| 787 | $result = db_query('SELECT pkid, title FROM {dpistudy_questions} ORDER BY weight, title'); |
| 788 | |
| 789 | while ($question = db_fetch_object($result)) { |
| 790 | $answers = array(); |
| 791 | $result2 = db_query('SELECT weight, answer FROM {dpistudy_answers} WHERE parent = %d ORDER BY weight', $question->pkid); |
| 792 | while ($answer = db_fetch_object($result2)) { |
| 793 | $answers[$answer->weight] = $answer->answer; |
| 794 | } |
| 795 | ksort($answers); // shouldn't be necessary, but just making sure |
| 796 | $questions['question_' . $i] = array( |
| 797 | '#type' => 'radios', |
| 798 | '#options' => $answers, |
| 799 | '#title' => $question->title, |
| 800 | '#prefix' => "<tr><td style=\"vertical-align: top; font-weight: bold\"><div class=\"form-item\">$i.</div></td><td>", |
| 801 | '#suffix' => '</td></tr>' |
| 802 | ); |
| 803 | $i++; |
| 804 | } |
| 805 | cache_set('dpistudy-questions', $questions); |
| 806 | } |
| 807 | |
| 808 | $form = array_merge($form, $questions); |
| 809 | unset($questions); |
| 810 | |
| 811 | $form['close_table'] = array( |
| 812 | '#type' => 'markup', |
| 813 | '#value' => '</table>' |
| 814 | ); |
| 815 | $form['request_time'] = array( |
| 816 | '#type' => 'hidden', |
| 817 | '#value' => $_SERVER['REQUEST_TIME'] |
| 818 | ); |
| 819 | $form['js_timer'] = array( |
| 820 | '#type' => 'hidden' |
| 821 | ); |
| 822 | $form['#redirect'] = 'dpistudy/instruction'; |
| 823 | $form['next'] = array( |
| 824 | '#value' => '<p>' . t('After clicking submit, you will be presented with 6 timed questions.') . '</p>' |
| 825 | ); |
| 826 | return array_merge($form, dpistudy_submit_form()); |
| 827 | } |
| 828 | |
| 829 | function dpistudy_dpi_questionnaire_form_submit($form, &$form_status) { |
| 830 | $times = _dpistudy_calculate_times( |
| 831 | $form_status['clicked_button']['#post']['microtime'], |
| 832 | $form_status['clicked_button']['#post']['request_time'], |
| 833 | $form_status['values']['js_timer'] |
| 834 | ); |
| 835 | |
| 836 | $num_questions = db_result(db_query('SELECT COUNT(*) FROM {dpistudy_questions}')); |
| 837 | for ($i=1; $i<=$num_questions; $i++) { |
| 838 | if (isset($form_status['values']["question_$i"])) { |
| 839 | db_query("INSERT INTO {dpistudy_responses} (sessid, question, answer, php_timer, apache_timer, js_timer) VALUES ('%s', %d, %d, '%f', %d, %d)", session_id(), $i, $form_status['values']["question_$i"], $times['microtime'], $times['http_header'], $times['javascript']); |
| 840 | } |
| 841 | } |
| 842 | } |
| 843 | |
| 844 | /** |
| 845 | * Cycle through questions for the instructional intervention |
| 846 | * Multiple choice questions should have one of the following |
| 847 | * sample behaviors according to Hirumi's verbal alignment: |
| 848 | * |
| 849 | * choose, discriminate, identify, recognize, select, solve, locate |
| 850 | * |
| 851 | * Verbs to match those behaviors at a verbal, knowledge level are: |
| 852 | * |
| 853 | * arrange, acquire, define, distinguish, duplicate, |
| 854 | * identify, label, list, match, memorize, name, |
| 855 | * order, recognize, recall, repeat, reproduce |
| 856 | * |
| 857 | * @return string |
| 858 | */ |
| 859 | function dpistudy_instruction_form() { |
| 860 | |
| 861 | $module_path = url(drupal_get_path('module', 'dpistudy'), array('absolute' => true)); |
| 862 | if (!isset($_SESSION['instruction_number'])) { |
| 863 | $_SESSION['instruction_number'] = 1; |
| 864 | } |
| 865 | |
| 866 | if (!isset($_SESSION['instructional_material_order'])) { |
| 867 | // counter balancing with randomization |
| 868 | $text = array(1, 2, 3); |
| 869 | $graphics = array(4, 5, 6); |
| 870 | shuffle($text); |
| 871 | shuffle($graphics); |
| 872 | if (mt_rand(0, 1)) { |
| 873 | $_SESSION['instructional_material_order'] = array_merge($text, $graphics); |
| 874 | } |
| 875 | else { |
| 876 | $_SESSION['instructional_material_order'] = array_merge($graphics, $text); |
| 877 | } |
| 878 | } |
| 879 | |
| 880 | $form = dpistudy_time_form(); |
| 881 | $form['question'] = array( |
| 882 | '#type' => 'value', |
| 883 | '#value' => $_SESSION['instructional_material_order'][$_SESSION['instruction_number']-1] // the key of the 1-6 questions, which is actually 0-5 |
| 884 | ); |
| 885 | |
| 886 | switch ($form['question']['#value']) { |
| 887 | case 6: |
| 888 | $form['instruct_q6'] = array( |
| 889 | '#type' => 'radios', |
| 890 | '#prefix' => '<p><img src="' . $module_path . '/images/Graph_TravelTimes.gif" height="520" width="589" alt="Travel Times Southbound Departing St. Canards Station" title="Travel Times Southbound Departing St. Canards Station" longdesc="Travel Times Southbound Departing St. Canards Station at 6:00 am. Travel time in minutes. 14 stops are listed in a horizontal bar chart. Springfield 10. Toontown 17. Glenoak 23. Faerie 27. Emerald City 36. Whoville 42. Nottinghamshire 47. Fantasia 49. Florin 51. Hogwarts 61. Fraggle Rock 67. Bedrock 73. Southpark 78. Hotel Denouement 84." /></p>', |
| 891 | '#title' => t('Based on the above chart, the travel time to Nottinghamshire is'), |
| 892 | '#options' => array( |
| 893 | t('<img src="' . $module_path . '/images/bar_42.gif" height="18" width="197" alt="blue bar" title="blue bar" longdesc="Horizontal blue bar matching the length of Whoville." />'), |
| 894 | t('<img src="' . $module_path . '/images/bar_51.gif" height="18" width="238" alt="blue bar" title="blue bar" longdesc="Horizontal blue bar matching the length of Florin." />'), |
| 895 | t('<img src="' . $module_path . '/images/bar_17.gif" height="18" width="79" alt="blue bar" title="blue bar" longdesc="Horizontal blue bar matching the length of Toontown." />'), |
| 896 | t('<img src="' . $module_path . '/images/bar_47.gif" height="18" width="214" alt="blue bar" title="blue bar" longdesc="Horizontal blue bar matching the length of Nottinghamshire." />') |
| 897 | ), |
| 898 | '#attributes' => array('class' => 'instruction-question') |
| 899 | ); |
| 900 | break; |
| 901 | case 5: |
| 902 | $form['instruct_q5_markup'] = array( |
| 903 | '#value' => '<p style="background-color:yellow; font-weight:bold;">Click on the Regional Intermodal Center for the I-Drive Circulator on Toll 417.</p>' |
| 904 | . '<p><map name="transit_routes_im" id="transit_routes_im">' |
| 905 | . '<area shape="circle" coords="380,507,8" href="javascript:dpistudy_q5(0);" alt="I-Drive Circulator" title="I-Drive Circulator" longdesc="Black dot with description saying I-Drive Circulator" />' |
| 906 | . '<area shape="circle" coords="385,554,11" href="javascript:dpistudy_q5(0);" alt="I-Drive Regional Intermodal Center" title="I-Drive Regional Intermodal Center" longdesc="White circle, with a red border, and a blue 5-point star in the center. I-Drive Regional Intermodal Center" />' |
| 907 | . '<area shape="circle" coords="471,436,11" href="javascript:dpistudy_q5(1);" alt="Orlando Regional Intermodal Center" title="Orlando Regional Intermodal Center" longdesc="White circle, with a red border, and a blue 5-point star in the center. Orlando Regional Intermodal Center" />' |
| 908 | . '<area shape="circle" coords="426,707,11" href="javascript:dpistudy_q5(2);" alt="Kissimmee Regional Intermodal Center" title="Kissimmee Regional Intermodal Center" longdesc="White circle, with a red border, and a blue 5-point star in the center. Kissimmee Regional Intermodal Center" />' |
| 909 | . '<area shape="circle" coords="619,163,11" href="javascript:dpistudy_q5(3);" alt="Sanford Regional Intermodal Center" title="Sanford Regional Intermodal Center" longdesc="White circle, with a red border, and a blue 5-point star in the center. Sanford Regional Intermodal Center" />' |
| 910 | . '<area shape="circle" coords="537,578,11" href="javascript:dpistudy_q5(4);" alt="OIA Regional Intermodal Center" title="OIA Regional Intermodal Center" longdesc="White circle, with a red border, and a blue 5-point star in the center. OIA Regional Intermodal Center" />' |
| 911 | . '</map><img src="' . $module_path . '/images/transit_routes.jpg" height="734" width="750" alt="Central Florida Commuter Rail Transit Routes map" title="Central Florida Commuter Rail Transit Routes map" longdesc="Central Florida Commuter Rail Transit Routes map has a key in the top left corner." usemap="#transit_routes_im" /></p>' |
| 912 | . '<p style="background-color:yellow; font-weight:bold;">Click on the Regional Intermodal Center for the I-Drive Circulator on Toll 417.</p>' |
| 913 | ); |
| 914 | $form['instruct_q5'] = array( |
| 915 | '#type' => 'hidden', |
| 916 | '#value' => '' |
| 917 | ); |
| 918 | break; |
| 919 | case 4: |
| 920 | $form['instruct_q4'] = array( |
| 921 | '#type' => 'radios', |
| 922 | '#prefix' => '<p><img src="' . $module_path . '/images/Graph_CapitalFundingDistribution.gif" height="314" width="302" alt="capital funding distribution" title="capital funding distribution" longdesc="Capital funding distribution." /><img src="' . $module_path . '/images/Graph_TypicalOMFundingSources.gif" height="314" width="300" alt="" title="" longdesc="" /></p>', |
| 923 | '#title' => t('Select the pie chart representation of "Equipment 18%"'), |
| 924 | '#options' => array( |
| 925 | t('<img src="' . $module_path . '/images/capital_funding_equipment.gif" height="121" width="150" alt="51" title="51" longdesc="Horizontal blue bar with the number 51 on the right side in white text." />'), |
| 926 | t('<img src="' . $module_path . '/images/funding_sources_subsidy.gif" height="141" width="150" alt="42" title="42" longdesc="Horizontal blue bar with the number 42 on the right side in white text." />'), |
| 927 | t('<img src="' . $module_path . '/images/capital_funding_station_costs.gif" height="96" width="189" alt="17" title="17" longdesc="Horizontal blue bar with the number 17 on the right side in white text." />'), |
| 928 | t('<img src="' . $module_path . '/images/funding_sources_fare_box_recovery.gif" height="107" width="151" alt="47" title="47" longdesc="Horizontal blue bar with the number 47 on the right side in white text." />') |
| 929 | ), |
| 930 | '#attributes' => array('class' => 'instruction-question') |
| 931 | ); |
| 932 | break; |
| 933 | case 3: |
| 934 | $form['instruct_q3'] = array( |
| 935 | '#type' => 'radios', |
| 936 | '#prefix' => '<ul><strong>DeLand/Orange City/DeBary/Volusia County</strong>' |
| 937 | . '<li style="margin-left: 2.5em">Nearly 50,000 people live in Orange City, DeBary and DeLand, one of the fastest growing areas of Volusia County</li>' |
| 938 | . '<li style="margin-left: 2.5em">Nearly a quarter of the workforce commutes to jobs outside the county, primarily to Seminole and Orange counties</li></ul>' |
| 939 | |
| 940 | . '<ul><strong>Sanford/Lake Mary/Longwood/Altamonte Springs</strong>' |
| 941 | |
| 942 | . '<li style="margin-left: 2.5em">Home to two major retail malls</li>' |
| 943 | . '<li style="margin-left: 2.5em">Growing business clusters along the I-4 corridor and individual communities</li>' |
| 944 | . '<li style="margin-left: 2.5em">County government located in Sanford</li>' |
| 945 | . '<li style="margin-left: 2.5em">Nearly 400,000 live in Seminole County</li>' |
| 946 | . '<li style="margin-left: 2.5em">More than 40 percent of workforce commutes to jobs in Orange County</li>' |
| 947 | . '<li style="margin-left: 2.5em">Passenger counts at Orlando-Sanford Airport nearly doubled between 2000 and 2004 Winter Park/Orlando/Orange County</li></ul>' |
| 948 | |
| 949 | . '<ul><strong>Winter Park/Orlando/Orange County</strong>' |
| 950 | |
| 951 | . '<li style="margin-left: 2.5em">Economic and cultural hub of Central Florida</li>' |
| 952 | . '<li style="margin-left: 2.5em">Home to NBA\'s Orlando Magic</li>' |
| 953 | . '<li style="margin-left: 2.5em">Intermodal transfers at Lynx Central Station and the Sand Lake area</li>' |
| 954 | . '<li style="margin-left: 2.5em">Federal/state/local government and educational activity centers</li>' |
| 955 | . '<li style="margin-left: 2.5em">Major renovations to the Citrus Bowl, the downtown arena and a new performing arts center planned</li>' |
| 956 | . '<li style="margin-left: 2.5em">Station stops at Florida Hospital Orlando and Orlando Regional Medical Center, two of the region\'s largest employers</li>' |
| 957 | . '<li style="margin-left: 2.5em">Ready access to retail, dining and cultural activities in Winter Park and downtown Orlando</li>' |
| 958 | . '<li style="margin-left: 2.5em">Amtrak transfer stations</li></ul>' |
| 959 | |
| 960 | . '<ul><strong>Kissimmee/Osceola County</strong>' |
| 961 | |
| 962 | . '<li style="margin-left: 2.5em">Line terminates at the 1,200-acre Poinciana Industrial Park, which now employs more than 1,600 workers with major expansions planned</li>' |
| 963 | . '<li style="margin-left: 2.5em">Nearly 56,000 residents live within the city limits of Kissimmee, one of the fastest growing counties in Central Florida</li>' |
| 964 | . '<li style="margin-left: 2.5em">Almost three-quarters of Kissimmee residents commute to jobs outside the city</li>' |
| 965 | . '<li style="margin-left: 2.5em">More than a third of residents work in the tourism or services industry</li></ul>', |
| 966 | '#title' => t('Question: In which of these cities do ¾ of residents commute to jobs outside the city'), |
| 967 | '#options' => array( |
| 968 | t('Lake Mary'), |
| 969 | t('DeLand and Orlando'), |
| 970 | t('Kissimmee'), |
| 971 | t('Longwood') |
| 972 | ), |
| 973 | '#attributes' => array('class' => 'instruction-question') |
| 974 | ); |
| 975 | break; |
| 976 | case 2: |
| 977 | $form['instruct_q2'] = array( |
| 978 | '#type' => 'radios', |
| 979 | '#prefix' => '<p>The clock\'s winding down on Orange County commissioners doing what the people elected them to do, and that\'s providing leadership.</p>' |
| 980 | . '<p>The commissioners say they support commuter rail.</p>' |
| 981 | . '<p>They say it will help relieve gridlock by speeding commuters aboard sleek Internet-fitted cars beginning in 2009.</p>' |
| 982 | . '<p>But trains don\'t run on peanuts -- and that\'s all the commissioners so far say they\'re willing to give commuter rail to make it go. Unlike their counterparts in Volusia, Seminole and Osceola counties, most commissioners in Orange County say the county shouldn\'t have to assume the costs of its stations beginning in 2017. That\'s the date when localities must take on rail\'s operations and maintenance costs.</p>' |
| 983 | . '<p>What they say they will do is pay just one-third of the operations and maintenance expenses of Winter Park and Maitland, two cities north of Orlando considering hosting stations. That\'s what passes for leadership? Passing the buck?</p>' |
| 984 | . '<p>Orange County commissioners will meet Tuesday, one week before Winter Park residents vote on paying for and hosting a station. Residents there in a survey have said they want commuter rail. But many fear the cost.</p>' |
| 985 | . '<p>County commissioners can relieve those fears by agreeing to fully fund Winter Park\'s share. They also should do the same for Maitland, which is wary of the expense of maintaining a station in 2017.</p>', |
| 986 | '#title' => t('Question: According to the above editorial exerpt, trains don\'t run on'), |
| 987 | '#options' => array( |
| 988 | t('gasoline.'), |
| 989 | t('diesel.'), |
| 990 | t('peanuts.'), |
| 991 | t('good intentions.') |
| 992 | ), |
| 993 | '#attributes' => array('class' => 'instruction-question') |
| 994 | ); |
| 995 | break; |
| 996 | case 1: |
| 997 | default: |
| 998 | $form['instruct_q1'] = array( |
| 999 | '#type' => 'radios', |
| 1000 | '#prefix' => '<p>Traffic congestion is a growing concern for those who live, work and visit Central Florida. As our region continues to grow at a staggering pace, that congestion will only get worse. Though there is no one magic bullet to solve our traffic woes, several different modes of transportation options working together - known as "intermodal" in transportation-speak - is a proven way to ease the gridlock.</p>' |
| 1001 | . '<p>That\'s why the Florida Department of Transportation (FDOT), in cooperation with local government officials in Orange, Seminole, Volusia and Osceola counties and the federal government, is looking at a commuter rail transit project to run along a 61-mile stretch of existing rail freight tracks in the four-county area.</p>' |
| 1002 | . '<p>The 31-mile Phase 1 segment would serve 10 stations, linking DeBary to Orlando. Service could begin as soon as 2009 - just as FDOT starts a major I-4 reconstruction project through the heart of Central Florida, from State Road 434 in Longwood to Kirkman Road in southwest Orange County.</p>', |
| 1003 | '#title' => t('Question: Referencing the paragraphs above, the definition of "intermodal" is'), |
| 1004 | '#options' => array( |
| 1005 | t('multiple transportation modes working together.'), |
| 1006 | t('riding a railroad.'), |
| 1007 | t('the average of two populations.'), |
| 1008 | t('having a single mode of transportation.') |
| 1009 | ), |
| 1010 | '#attributes' => array('class' => 'instruction-question') |
| 1011 | ); |
| 1012 | break; |
| 1013 | } |
| 1014 | $form['request_time'] = array( |
| 1015 | '#type' => 'hidden', |
| 1016 | '#value' => $_SERVER['REQUEST_TIME'] |
| 1017 | ); |
| 1018 | if ($_SESSION['instruction_number'] == 6) { |
| 1019 | $form['#redirect'] = 'dpistudy/score'; |
| 1020 | } |
| 1021 | return array_merge($form, dpistudy_submit_form()); |
| 1022 | } |
| 1023 | |
| 1024 | function dpistudy_instruction_form_submit($form, &$form_status) { |
| 1025 | $times = _dpistudy_calculate_times( |
| 1026 | $form_status['clicked_button']['#post']['microtime'], |
| 1027 | $form_status['clicked_button']['#post']['request_time'], |
| 1028 | $form_status['values']['js_timer'] |
| 1029 | ); |
| 1030 | |
| 1031 | if (isset($form_status['values']["instruct_q{$form_status['values']['question']}"])) { |
| 1032 | db_query("INSERT INTO {dpistudy_responses} (sessid, question, answer, php_timer, apache_timer, js_timer) VALUES ('%s', '%s', '%s', '%f', %d, %d)", session_id(), $form_status['values']['question']+99, $form_status['values']["instruct_q{$form_status['values']['question']}"]+1, $times['microtime'], $times['http_header'], $times['javascript']); |
| 1033 | } |
| 1034 | |
| 1035 | $_SESSION['instruction_number']++; |
| 1036 | } |
| 1037 | |
| 1038 | function dpistudy_score() { |
| 1039 | $num_responses = 0; |
| 1040 | $dpi_score = 0; |
| 1041 | $incomplete = false; |
| 1042 | |
| 1043 | $result = db_query("SELECT r.answer FROM {dpistudy_responses} AS r LEFT JOIN {dpistudy_questions} AS q ON r.question = q.pkid WHERE r.question <= 34 AND r.answer <> 0 AND r.sessid = '%s'", session_id()); |
| 1044 | |
| 1045 | while ($response = db_fetch_object($result)) { |
| 1046 | $num_responses++; |
| 1047 | $dpi_score += $response->answer; |
| 1048 | } |
| 1049 | for ($i=34; $i>$num_responses; $i--) { |
| 1050 | $incomplete = true; |
| 1051 | $dpi_score += 3; |
| 1052 | } |
| 1053 | if ($incomplete == true) { |
| 1054 | drupal_set_message(t('Since you did not answer every question regarding Digital Propensity, your score is estimated.'), 'status', false); |
| 1055 | } |
| 1056 | |
| 1057 | dpistudy_protect_anonymity(); |
| 1058 | |
| 1059 | return t(variable_get('dpistudy_score_screen', ''), array('@score' => $dpi_score)); |
| 1060 | } |
| 1061 | |
| 1062 | /** |
| 1063 | * Destroy the session data and cookie. |
| 1064 | * |
| 1065 | * Calling user_logout() or sess_regenerate() would be similar |
| 1066 | * but since this is more messy, it makes sure we don't keep a |
| 1067 | * link to who the user is since it sets the existing cookie to |
| 1068 | * expire, then sets a totally different id that we never logged |
| 1069 | * in the database. |
| 1070 | */ |
| 1071 | function dpistudy_protect_anonymity() { |
| 1072 | $_SESSION = array(); |
| 1073 | sess_destroy_sid(session_id()); |
| 1074 | if (isset($_COOKIE[session_name()])) { |
| 1075 | setcookie(session_name(), '', time() - 42000, '/'); |
| 1076 | } |
| 1077 | session_regenerate_id(TRUE); |
| 1078 | } |
| 1079 | |
| 1080 | /** |
| 1081 | * |
| 1082 | * |
| 1083 | * @return array |
| 1084 | */ |
| 1085 | function dpistudy_time_form() { |
| 1086 | $form = array(); |
| 1087 | $form['js_timer'] = array( |
| 1088 | '#type' => 'textfield', |
| 1089 | '#title' => t('This question is timed'), |
| 1090 | '#size' => 7, |
| 1091 | '#maxlength' => 9, |
| 1092 | '#default_value' => '' |
| 1093 | ); |
| 1094 | return $form; |
| 1095 | } |
| 1096 | |
| 1097 | /** |
| 1098 | * Contains the form elements that make the PHP-based and |