/[drupal]/contributions/modules/uts/uts.pages.inc
ViewVC logotype

Contents of /contributions/modules/uts/uts.pages.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.38 - (show annotations) (download) (as text)
Tue Aug 18 02:51:42 2009 UTC (3 months, 1 week ago) by boombatower
Branch: MAIN
CVS Tags: HEAD
Changes since 1.37: +2 -1 lines
File MIME type: text/x-php
#512902: Add link on create new study on dashboard.
1 <?php
2 // $Id: uts.pages.inc,v 1.37 2009/01/12 01:22:11 boombatower Exp $
3 /**
4 * @file
5 * Provide interface pages.
6 *
7 * Copyright 2008 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
8 */
9
10 /**
11 * Display list of active studies to choose from.
12 *
13 * @return string HTML output.
14 */
15 function uts_participate_list() {
16 $out = '<p>' . t('Thanks for participating in our studies for making Drupal better. Please follow the steps.') . '</p>';
17
18 $studies = array_merge(uts_studies_load(UTS_STUDY_STATUS_ACTIVE));
19 foreach ($studies as $study) {
20 $out .= '<div class="uts-choose-study">';
21 $out .= l($study->title, 'uts/environment/' . $study->nid);
22 $teaser = node_teaser($study->body, NULL, 300);
23 $out .= '<p>' . $study->body . '</p>';
24 $out .= '</div>';
25 }
26
27 if (!$studies) {
28 $out = '<p>' . t('No active studies.') . '</p>';
29 }
30
31 return $out;
32 }
33
34 /**
35 * Create an environment for the session.
36 *
37 * @param integer $study_nid Study NID to display.
38 */
39 function uts_participate_create_environment_form(&$form_state, $study_nid) {
40 $study = node_load($study_nid);
41
42 $form = array();
43 $form['#validate'][] = 'uts_participate_create_environment_form_validate';
44 $form['study_nid'] = array(
45 '#type' => 'value',
46 '#value' => $study_nid
47 );
48 $form['instructions'] = array(
49 '#type' => 'item',
50 '#value' => t('In order to participate you must create an environment for your session.')
51 );
52
53 $form += uts_participate_requirements($study);
54
55 $form['op'] = array(
56 '#type' => 'submit',
57 '#value' => t('Create')
58 );
59
60 return $form;
61 }
62
63 /**
64 * Make sure that there is still room in the study for another paritipant.
65 */
66 function uts_participate_create_environment_form_validate($form, &$form_state) {
67 // Check the number of existing sessions against the maximum participant count.
68 $study = node_load($form_state['values']['study_nid']);
69 $sessions = uts_session_load_all($study->nid);
70 if (count($sessions) >= $study->participant_count) {
71 form_set_error('study_nid', t('The study is no longer open to new participants. Please try a different study.'));
72 drupal_goto('uts');
73 }
74 }
75
76 /**
77 * Start the batch process to create the session environment.
78 */
79 function uts_participate_create_environment_form_submit($form, &$form_state) {
80 uts_participate_environment_batch($form_state['values']['study_nid']);
81 }
82
83 /**
84 * Start a session.
85 *
86 * @param string $session_id UTS session ID.
87 */
88 function uts_participate_start_session_form(&$form_state, $session_id) {
89 $session = uts_session_load($session_id);
90
91 if (!$session) {
92 drupal_set_message(t('Invalid session ID.'), 'error');
93 drupal_goto('uts');
94 }
95
96 $study = node_load($session->study_nid);
97
98 $form = array();
99 $form['session_id'] = array(
100 '#type' => 'value',
101 '#value' => $session->session_id
102 );
103 $form['instructions'] = array(
104 '#type' => 'item',
105 '#value' => t('Start/Restore your session in which you are participating in %study.', array('%study' => $study->title))
106 );
107
108 $form += uts_participate_requirements($study);
109
110 $form['op'] = array(
111 '#type' => 'submit',
112 '#value' => t('Start')
113 );
114
115 return $form;
116 }
117
118 /**
119 * Start the batch process to configure the session.
120 */
121 function uts_participate_start_session_form_submit($form, &$form_state) {
122 uts_participate_session_batch($form_state['values']['session_id'], $form_state['values']['data_collection']);
123 }
124
125 /**
126 * Create form elements for the data plug-in requirements.
127 *
128 * @param object $study Study object.
129 * @return array Addition to root of form definition array.
130 */
131 function uts_participate_requirements($study) {
132 $form = array();
133 $plugins = uts_data_collection_list();
134 $requirements = uts_data_client_requirements();
135
136 $form['#validate'][] = 'uts_participate_requirements_validate';
137
138 // Check for javascript requirement.
139 foreach ($plugins as $module => $plugin) {
140 if ($plugin['javascript'] && $study->data_collection[$module]['required']) {
141 $form['requirements']['javascript_status'] = array(
142 '#type' => 'hidden',
143 '#default_value' => 'not-found'
144 );
145 $form['requirements'][] = array(
146 '#type' => 'markup',
147 '#value' => '<div class="uts-requirement error" id="uts-javascript">' .
148 t('Javascript is not enabled. Please turn it on.') .
149 '</div>'
150 );
151 drupal_add_js('$("div#uts-javascript").hide(); $("input#edit-javascript-status").attr("value", "found");', 'inline', 'footer');
152 break;
153 }
154 }
155
156 $form['data_collection'] = array(
157 '#type' => 'value',
158 '#tree' => TRUE
159 );
160 foreach ($requirements as $module => $requirement) {
161 if (array_key_exists($module, $study->data_collection)) {
162 if ($study->data_collection[$module]['required'] &&
163 $requirement['status'] != 'ok') {
164 $form['requirements'][] = array(
165 '#type' => 'markup',
166 '#value' => '<div class="uts-requirement ' . $requirement['status'] . '" id="' . $module . '">' .
167 $requirement['description'] .
168 '</div>'
169 );
170 }
171 $form['data_collection'][$module] = array(
172 '#type' => 'value',
173 '#value' => $requirement['status']
174 );
175 }
176 }
177
178 return $form;
179 }
180
181 /**
182 * Ensure that all the requirements have been met.
183 */
184 function uts_participate_requirements_validate($form, &$form_state) {
185 // Check JavaScript requirement.
186 if (isset($form_state['values']['javascript_status']) && $form_state['values']['javascript_status'] != 'found') {
187 form_set_error('javascript_status', t('Javascript must be enabled.'));
188 }
189
190 // Check data plug-in requirements.
191 $requirements = uts_data_client_requirements();
192 foreach ($requirements as $module => $requirement) {
193 foreach ($form_state['values']['data_collection'] as $module => $status) {
194 if ($status != 'ok') {
195 form_set_error($module . '_status', $requirement['description']);
196 }
197 }
198 }
199 }
200
201 /**
202 * Landing page after a participant completes a study.
203 *
204 * @param boolean $return Remind participant to return in order to finish their study.
205 */
206 function uts_participate_thanks($return = FALSE) {
207 if ($return) {
208 drupal_set_message(t('Remember to come back and finish your study.'));
209 }
210 return t('<p>We appreciate you taking the time to participate in our study.</p>
211 <p>Have a nice day.</p>');
212 }
213
214 /**
215 * Dashboard displayed on admin/uts as the main landing page. If no studies
216 * displays instructional video(s), otherwise summary view.
217 *
218 * @return string HTML output.
219 */
220 function uts_dashboard() {
221 drupal_add_css(drupal_get_path('module', 'uts') . '/uts.css', 'module');
222 $studies = uts_studies_load();
223
224 $out = '';
225 $out .= '<div style="float: right"><a href="/admin/uts/studies/add" style="border: 1px solid; padding: 10px;">' . t('Create study') . '</a></div>';
226 if (!$studies) {
227 $out .= t('<p>Running a usability test will give you valuable data to improve your application.
228 Getting feedback from real people using your module is the best feedback you can get.
229 The usability testing suite allows you to easily collect exactly that data!</p>');
230 $out .= '<div class="uts-dashboard">';
231 $out .= l(t('Create study'), 'admin/uts/studies/add', array('attributes' => array('id' => 'uts-create-study')));
232 $out .= '<h3 id="uts-learn">' . t('Learn about UTS, watch a video.') . '</h3>';
233 $out .= '<embed src="http://blip.tv/play/AaXwG4mSHQ" type="application/x-shockwave-flash" width="640" height="510" allowscriptaccess="always" allowfullscreen="true"></embed>';
234 $out .= '</div>';
235 }
236 else {
237 $out .= '<div id="uts-dashboard-summary">' . uts_dashboard_studies($studies) . '</div>';
238 }
239
240 return $out;
241 }
242
243 /**
244 * Display the summary of studies and participant progress.
245 *
246 * @param array $studies List of studies.
247 * @return string HTML output.
248 */
249 function uts_dashboard_studies($studies) {
250 $header = array(t('Name'), t('Participants'), t('Task progress'));
251 $rows = array();
252
253 // Cycle through studies to generate summary table.
254 foreach ($studies as $study) {
255 $progress = uts_dashboard_studies_progress($study);
256 $tasks = uts_tasks_load($study->nid);
257
258 $row = array();
259 $row[] = array(
260 'data' => l($study->title, 'node/' . $study->nid),
261 'id' => $study->nid
262 );
263 $row[] = t('@count / @required', array('@count' => $progress['overal']['participated'], '@required' => $study->participant_count));
264 $row[] = theme('uts_progress', $progress['overal']['completed'], count($tasks) * $study->participant_count);
265
266 $rows[] = $row;
267
268 // Generate individual task rows.
269 foreach ($tasks as $task) {
270 $row = array();
271 $row[]['data'] = l($task->title, 'node/' . $task->nid);
272 $row[] = t('@count / @required', array('@count' => $progress[$task->nid]['participated'], '@required' => $study->participant_count));
273 $row[] = theme('uts_progress', $progress[$task->nid]['completed'], $study->participant_count);
274
275 $rows[] = $row;
276 }
277 }
278
279 return theme('uts_dashboard_studies', $header, $rows);
280 }
281
282 /**
283 * Add collapse/expand JavaScript to table rows.
284 *
285 * @return string HTML output.
286 */
287 function theme_uts_dashboard_studies($header, $rows) {
288 drupal_add_js(drupal_get_path('module', 'uts') . '/uts.js');
289
290 $js = array(
291 'images' => array(
292 theme('image', 'misc/menu-collapsed.png', 'Expand', 'Expand'),
293 theme('image', 'misc/menu-expanded.png', 'Collapsed', 'Collapsed'),
294 ),
295 );
296
297 foreach ($rows as $key => $row) {
298 $name = $rows[$key][0]['data'];
299 if ($id = $rows[$key][0]['id']) {
300 $last_study_id = 'uts-study-' . $id;
301 $rows[$key][0] = array(
302 'data' => '<div class="uts-image" id="' . $last_study_id . '"></div>' . $name,
303 'class' => 'uts-study',
304 'style' => 'font-weight: bold;'
305 );
306 $js[$last_study_id] = array(
307 'imageDirection' => 0 // Collapsed.
308 );
309 }
310 else {
311 $rows[$key][0] = theme('indentation', 1) . $name;
312 $rows[$key] = array(
313 'data' => $rows[$key],
314 'class' => $last_study_id . '-task uts-task',
315 'style' => 'display: none;'
316 );
317 }
318 }
319 drupal_add_js(array('uts' => $js), 'setting');
320 return theme('table', $header, $rows);
321 }
322
323 /**
324 * Calculate the progress made overal and per task for the specified study.
325 *
326 * @param object $study Study object.
327 * @return array Progress overal and per task.
328 */
329 function uts_dashboard_studies_progress($study) {
330 $sessions = uts_session_load_all($study->nid);
331
332 // Get the number of sessions that completed each task.
333 $tasks = uts_tasks_load($study->nid);
334
335 // Initialize all progress results to 0.
336 $progress = array();
337 $progress['overal']['completed'] = 0;
338 $progress['overal']['participated'] = count($sessions);
339 foreach ($tasks as $task) {
340 $progress[$task->nid]['completed'] = 0;
341 $progress[$task->nid]['participated'] = 0;
342 }
343
344 // Collect task progress data based on the related sessions.
345 foreach ($sessions as $session_id) {
346 $session = uts_session_load($session_id);
347
348 if ($session->complete) {
349 // Session completed all tasks.
350 foreach ($tasks as $task) {
351 $progress['overal']['completed']++;
352 $progress[$task->nid]['completed']++;
353 $progress[$task->nid]['participated']++;
354 }
355 }
356 else {
357 // See how far the session has progressed.
358 foreach ($tasks as $task) {
359 if ($session->current_task != $task->nid) {
360 // Made it past this task.
361 $progress['overal']['completed']++;
362 $progress[$task->nid]['completed']++;
363 $progress[$task->nid]['participated']++;
364 }
365 else {
366 $progress[$task->nid]['participated']++;
367 break;
368 }
369 }
370 }
371 }
372 return $progress;
373 }
374
375 /**
376 * Theme a progress bar.
377 *
378 * @param integer $progress Progress part out of total.
379 * @param integer $total Total required.
380 * @return string HTML output.
381 */
382 function theme_uts_progress($progress, $total) {
383 if ($total) {
384 $part = round(($progress / $total) * 100);
385 $whole = 100 - $part;
386 }
387 return '<div id="uts-dashboard-progess">' . ($total ?
388 '<div id="uts-dashboard-progess-part" style="width: ' . $part . 'px;"></div>' .
389 '<div id="uts-dashboard-progess-whole" style="width: ' . $whole . 'px;"></div>' : '') .
390 '</div>';
391 }
392
393 /**
394 * Send invitations to people asking them to participate.
395 */
396 function uts_invite(&$form_state) {
397 $form = array();
398
399 // Get list of studies for select.
400 $studies = uts_studies_load();
401 $list = array();
402 $list[] = t('--');
403 foreach ($studies as $study) {
404 $list[$study->nid] = $study->title;
405 }
406
407 $form['study_nid'] = array(
408 '#type' => 'select',
409 '#title' => t('Study'),
410 '#options' => $list,
411 );
412 $form['addresses'] = array(
413 '#type' => 'textarea',
414 '#title' => t('E-mail addresses'),
415 '#description' => t('List of e-mail addresses on separate lines to send the invites to. If the person\'s
416 name is specified using the syntax <em>Name, email@example.com</em> then the parameter
417 !name will use the person\'s name otherwise the e-mail address will be used.'),
418 '#rows' => 10
419 );
420 $form['send'] = array(
421 '#type' => 'submit',
422 '#value' => t('Send')
423 );
424
425 return $form;
426 }
427
428 /**
429 * Validate the addresses.
430 */
431 function uts_invite_validate($form, &$form_state) {
432 $addresses = explode("\n", $form_state['values']['addresses']);
433
434 $line = 1;
435 foreach ($addresses as $address) {
436 $parts = explode(',', $address);
437 if (count($parts) > 2) {
438 form_set_error('addresses', t('To many comma separated parts on line @line.',
439 array('@line' => $line)));
440 }
441 $email = trim(count($parts) == 1 ? $parts[0] : $parts[1]);
442 if (!valid_email_address($email)) {
443 form_set_error('addresses', t('Invalid e-mail address %address on line @line.',
444 array('%address' => $email, '@line' => $line)));
445 }
446 $line++;
447 }
448 }
449
450 /**
451 * Send the invites.
452 */
453 function uts_invite_submit($form, &$form_state) {
454 global $user;
455 $addresses = explode("\n", $form_state['values']['addresses']);
456
457 // Cycle through addresses.
458 foreach ($addresses as $address) {
459 $params = array();
460 $params['account'] = $user;
461
462 $parts = explode(',', $address);
463 if (count($parts) == 1) {
464 $params['name'] = $to = trim($parts[0]);
465 }
466 else {
467 $params['name'] = trim($parts[0]);
468 $to = t('"@name" <!address>', array('@name' => $params['name'], '!address' => trim($parts[1])));
469 }
470
471 if ($form_state['values']['study_nid']) {
472 $params['study_nid'] = $form_state['values']['study_nid'];
473 }
474 drupal_mail('uts', 'invite', $to, user_preferred_language($user), $params);
475 }
476 drupal_set_message(t('@count invites sent.', array('@count' => count($addresses))));
477 }
478
479 /**
480 * Task import page.
481 *
482 * @param interger $study_nid Study NID to import tasks for.
483 * @return array Form output.
484 */
485 function uts_import_tasks(&$form_state, $study_nid = NULL) {
486 $form = array();
487 $form['study_nid'] = array(
488 '#type' => 'value',
489 '#value' => $study_nid
490 );
491
492 if ($study_nid) {
493 uts_set_title($study_nid, 'Import tasks');
494
495 // Only import sources from existing database if they will be related to a study.
496 $form['existing_source'] = array(
497 '#type' => 'fieldset',
498 '#title' => t('Existing Source'),
499 '#description' => t('Import tasks from database.'),
500 '#weight' => -10
501 );
502 $form['existing_source']['tasks'] = array(
503 '#type' => 'select',
504 '#title' => t('Tasks'),
505 '#multiple' => TRUE,
506 '#weight' => -10
507 );
508 // Add options.
509 $tasks = uts_tasks_load(NULL, TRUE);
510 $options = array();
511 foreach ($tasks as $task) {
512 $options[$task->nid] = $task->title;
513 }
514 $form['existing_source']['tasks']['#options'] = $options;
515 $form['existing_source']['tasks']['#size'] = min(6, count($options));
516 }
517 else {
518 drupal_set_title(t('Import tasks'));
519 }
520
521 $form['xml_source'] = array(
522 '#type' => 'fieldset',
523 '#title' => t('XML Source'),
524 '#description' => t('Import tasks from an XML source.'),
525 '#weight' => -9
526 );
527 $form['xml_source']['file'] = array(
528 '#type' => 'file',
529 '#title' => t('Source'),
530 '#description' => t('Correctly formed XML document containing UTS tasks.'),
531 '#disabled' => TRUE, // TODO
532 '#weight' => -10
533 );
534
535 $form['import'] = array(
536 '#type' => 'submit',
537 '#value' => 'Import',
538 '#weight' => -8
539 );
540
541 return $form;
542 }
543
544 /**
545 * Execute import either from XML or non-related tasks in database.
546 */
547 function uts_import_tasks_submit($form, &$form_state) {
548 // Tasks from database.
549 if (isset($form_state['values']['tasks']) && count($form_state['values']['tasks']) > 0) {
550 uts_tasks_import($form_state['values']['study_nid'], $form_state['values']['tasks']);
551 }
552
553 // TODO Tasks from XML.
554 }
555
556 /**
557 * Menu callback -- ask for confirmation of task detaching then redirect
558 * to appropriate overview page.
559 */
560 function uts_task_detach_confirm(&$form_state, $task) {
561 $type = node_get_types('type', $task);
562 if ($type->orig_type != UTS_TASK) {
563 drupal_set_message(t('Must be task to detach from study.'));
564 drupal_goto('admin/uts/tasks');
565 }
566 $study = node_load($task->study_nid);
567 $redirect = 'admin/uts/tasks/' . $study->nid;
568
569 // Inject form values.
570 $form['task_nid'] = array(
571 '#type' => 'value',
572 '#value' => $task->nid,
573 );
574 $form['redirect'] = array(
575 '#type' => 'value',
576 '#value' => $redirect,
577 );
578
579 return confirm_form($form,
580 t('Are you sure you want to detach %task from %study?', array('%task' => $task->title, '%study' => $study->title)),
581 isset($_GET['destination']) ? $_GET['destination'] : $redirect,
582 t('This action cannot be undone.'),
583 t('Detach'),
584 t('Cancel')
585 );
586 }
587
588 /**
589 * Execute task detaching.
590 */
591 function uts_task_detach_confirm_submit($form, &$form_state) {
592 if ($form_state['values']['confirm']) {
593 $task = node_load($form_state['values']['task_nid']);
594 $study = node_load($task->study_nid);
595 db_query('UPDATE {uts_task}
596 SET study_nid = NULL,
597 weight = NULL
598 WHERE nid = %d', $task->nid);
599 drupal_set_message(t('%task was detached from %study.', array('%task' => $task->title, '%study' => $study->title)));
600 }
601
602 // Set the redirect to the pre-determined location.
603 $form_state['redirect'] = $form_state['values']['redirect'];
604 }
605
606 /**
607 * Menu callback -- ask for confirmation of node deletion then redirect
608 * to appropriate overview page.
609 */
610 function uts_delete_confirm(&$form_state, $node) {
611 $message = t('This action cannot be undone.');
612
613 // Decide on the redirect url.
614 $type = node_get_types('type', $node);
615 if ($type->orig_type == UTS_STUDY) {
616 $redirect = 'admin/uts/studies';
617 $message .= t(' Related tasks and session data will also be removed.');
618 }
619 else if ($type->orig_type == UTS_TASK) {
620 $redirect = 'admin/uts/tasks' . ($node->study_nid ? '/' . $node->study_nid : '');
621 }
622 else if ($type->orig_type == UTS_ENVIRONMENT) {
623 $redirect = 'admin/uts/environments';
624 }
625
626 // Inject form values.
627 $form['nid'] = array(
628 '#type' => 'value',
629 '#value' => $node->nid,
630 );
631 $form['redirect'] = array(
632 '#type' => 'value',
633 '#value' => $redirect,
634 );
635
636 return confirm_form($form,
637 t('Are you sure you want to delete %title?', array('%title' => $node->title)),
638 isset($_GET['destination']) ? $_GET['destination'] : $redirect,
639 $message,
640 t('Delete'),
641 t('Cancel')
642 );
643 }
644
645 /**
646 * Execute node deletion.
647 */
648 function uts_delete_confirm_submit($form, &$form_state) {
649 if ($form_state['values']['confirm']) {
650 node_delete($form_state['values']['nid']);
651 }
652
653 // Set the redirect to the pre-determined location.
654 $form_state['redirect'] = $form_state['values']['redirect'];
655 }

  ViewVC Help
Powered by ViewVC 1.1.2