View difference between Paste ID: Eys9DQf0 and 5gVnameJ
SHOW: | | - or go back to the newest paste.
1
<?php
2
// $Id$
3
/*
4
 * @file allocated_seating.module
5
 * Provides form elements to enable other modules to define allocated seating
6
 * and collect user input
7
 * @copyright Copyright(c) 2010 Lee Rowlands
8
 * @license GPL v2 http://www.fsf.org/licensing/licenses/gpl.html 
9
 * @author Lee Rowlands leerowlands at rowlands-bcs dot com
10
 * 
11
 */
12
13
/**
14
 * Implementation of hook_menu().
15
 */
16
function allocated_seating_menu() {
17
  //generic Call handler, append args to return specific form elements
18
19
  $items['allocated_seating/ajax'] = array(
20
    'title'            => 'Generic Call handler',
21
    'delivery callback' => 'drupal_json_output',
22
    'page callback'    => 'allocated_seating_ajax',
23
    'access arguments' =>  array('create seating plans'),
24
    'type'             => MENU_CALLBACK
25
  );
26
  return $items;
27
} 
28
29
30
/**
31
 * Implements hook_permission
32
*/
33
34
function  allocated_seating_permission() {
35
  return array(
36
    'create seating plans' => array(
37
      'title' => t('Create seating plans'),
38
    )
39
  );
40
}
41
42
/**
43
 * Implementation of hook_elements_info().
44
 */
45
function allocated_seating_element_info() {
46
  $type['allocated_seating_seat_design'] = array(
47
    '#input' => TRUE,
48
    '#tree' => TRUE,
49
    '#default_value' => array(
50
      'seats' => 40,
51
      'row_count' => 2,
52
      'floor_count' => 1,
53
      'floors' => array(),
54
    ),
55
    '#process' => array('allocated_seating_seat_design_process'),
56
    '#theme' => array('allocated_seating_seat_design'),
57
  );
58
  
59
  $type['allocated_seating_seat_select'] = array(
60
    '#input' => TRUE,
61
    '#tree' => TRUE,
62
    '#process' => array('allocated_seating_seat_select_process'),
63
    '#element_validate' => array('allocated_seating_seat_select_validate'),    
64
    '#required_seats' => NULL,
65
  );
66
  return $type;
67
}
68
69
70
/**
71
 * Implementation of hook_theme().
72
 */
73
function allocated_seating_theme($existing, $type, $theme, $path) {
74
  return array(
75
    'allocated_seating_seat_design' => array(
76
      'arguments' => array('element' => NULL),
77
    ),
78
    'allocated_seating_seat_select' => array(
79
      'arguments' => array('element' => NULL),
80
    ),
81
    'allocated_seating_seat_available' => array(
82
      'arguments' => array('plan' => array(),
83
                           'not_available' => array()
84
                          ),
85
    ),
86
  );
87
}
88
89
/**
90
 * Provides processing to expand the form element
91
*/
92
function allocated_seating_seat_select_process($element, $form_state, $complete_form) {
93
  if (empty($element['#plan'])) {
94
    //no floor plan!
95
    return;
96
  }
97
  $plan = $element['#plan'];
98
  if (!$element['#not_available']) {
99
    $element['#not_available'] = array();
100
  }
101
  $blank = 1;
102
  $parents = $element['#parents'];
103
  $element['floors'] = array(
104
    '#tree' => FALSE, //we structure the data in a nest for theming but only want seat# => 1/0
105
    '#parents' => array_merge($parents, array('floors'))
106
  );
107
  foreach ($plan['floors'] as $f => $floor) {
108
    $element['floors'][$f] = array(
109
      '#tree' => FALSE,
110
      '#col_count' => $floor['col_count'],
111
      'title' => array(
112
        '#value' => $floor['title']
113
      ),
114
      'rows' => array(
115
        '#tree' => FALSE,
116
      )  
117
    );
118
    foreach ($floor['rows'] as $r => $row) {
119
      $element['floors'][$f]['rows'][$r] = array(
120
        '#tree' => FALSE,
121
        'columns' => array(
122
          '#tree' => FALSE,
123
          '#parents' => array_merge($parents, array('floors', $f, 'rows', $r, 'columns')),
124
        )
125
      );
126
      foreach ($row['columns'] as $c => $column) {
127
        if ($column['seat'] &&
128
            is_numeric($column['seat']) &&
129
            !in_array($column['seat'], $element['#not_available'])) {
130
          //add the seat checkbox
131
          $element['floors'][$f]['rows'][$r]['columns'][$column['seat']] = array(
132
            '#attributes' => array('class' => 'allocated-seating-seat'),
133
            '#type' => 'checkbox',
134
            '#parents' => array('seats', $column['seat']),
135
            '#title' => $column['seat']
136
          );
137
        }
138
        else {
139
          //add the blank
140
          $element['floors'][$f]['rows'][$r]['columns']['b_'. $blank] = array(
141
            '#value' => '&nbsp;'
142
          );
143
          $blank++;
144
        }
145
      }
146
    }
147
  }
148
  return $element;
149
}
150
151
/**
152
 * Provides processing to expand the form element
153
*/
154
function allocated_seating_seat_design_process($element, $form_state, $complete_form) {
155
  static $plan,$post_static;
156
  // Cache the submitted $_POST data.
157
  if (!empty($element['#post']) || $post_static === NULL) {
158
    if (count($element['#array_parents']) == 1) {
159
      $post = &$element['#post'][$element['#array_parents'][0]];
160
      $post_static = $element['#post'][$element['#array_parents'][0]];
161
    }
162
    elseif (count($element['#array_parents']) == 2) {
163
      $post = &$element['#post'][$element['#array_parents'][0]][$element['#array_parents'][1]];
164
      $post_static = $element['#post'][$element['#array_parents'][0]][$element['#array_parents'][1]];
165
    }
166
    elseif (count($element['#array_parents']) == 3) {
167
      $post = &$element['#post'][$element['#array_parents'][0]][$element['#array_parents'][1]][$element['#array_parents'][2]];
168
      $post_static = $element['#post'][$element['#array_parents'][0]][$element['#array_parents'][1]][$element['#array_parents'][2]];
169
    }
170
    else {
171
      $post = array();
172
      $post_static = array();
173
    }
174
  }
175
  $all_defaults = array();
176
  $all_defaults['allocated_seating_seat_design'] = element_info('allocated_seating_seat_design');
177
  $defaults = $all_defaults['allocated_seating_seat_design']['#default_value'];
178
  // Ensure there are correct defaults.
179
  foreach ($all_defaults['allocated_seating_seat_design']['#default_value'] as $var => $default) {
180
    if (empty($element['#value'][$var])) {
181
      $element['#value'][$var] = $default;
182
    }
183
  }
184
  if (empty($element['#seats'])) {
185
    //must know the # of seats!
186
    return array(
187
      '#value' => t('Did not receive number of seats for the design, cannot proceed. Please set the #seats element attribute.')
188
    );
189
  }
190
 if (empty($plan)) {
191
    if (empty($element['#value']['floors'])) {
192
    $default = array(
193
      'floors' => array(
194
        array(
195
          'title' => t('Floor 1'),
196
          'rows' => array()
197
        )
198
      )
199
    );//the default
200
    $cols = ceil($element['#seats'] / 4); //default 4 rows
201
    $row = 0;
202
    $s = 1;
203
    while ($row < 4) {
204
      $col = 0;
205
      $default['floors'][0]['rows'][$row] = array('columns' => array()); //add the rows
206
      while ($col < $cols) {
207
        if ($s <= $element['#seats']) {
208
          $seat = $s;
209
          $s++;
210
        }
211
        else {
212
          $seat = FALSE;
213
        }
214
        $default['floors'][0]['rows'][$row]['columns'][] = array('seat' => $seat); //add the seat
215
        $col++;
216
      }
217
      $row++;
218
    }
219
    $element['#value'] = $default;
220
  }
221
  else {
222
      // Check if a new floor needs to be added.
223
      if (!empty($form_state['post']['_triggering_element_name']) && $form_state['post']['_triggering_element_value'] == t('Add floor')) {
224
        $element['#value'] =  $_POST['ticket_plan'];
225
        allocated_seating_plan_add_floor($element, $post);
226
      }
227
    //make sure our seats matches the number in the plan
228
    $real_seats = allocated_seating_real_seats($element['#value']);
229
    $needed_seats = $element['#seats'];
230
    //do we have enough?
231
    $total_seats = allocated_seating_plan_seats($element['#value']);
232
    while ($total_seats < $needed_seats) {
233
      allocated_seating_plan_floor_add_row($element['#value'], 0);
234
      $total_seats = allocated_seating_plan_seats($element['#value']);
235
    }
236
    if ($needed_seats != $real_seats) {
237
      //we have an issue here
238
      $seat_map = allocated_seating_get_map($element['#value']);
239
      $blanks = $seat_map['blanks'];
240
      if ($needed_seats < $real_seats) {
241
        //we need to remove some seats
242
        while ($needed_seats < $real_seats) {
243
          $remove = $seat_map['seats'][$real_seats];
244
          if ($remove) {
245
            $element['#value']['floors'][$remove['floor']]['rows'][$remove['row']]['columns'][$remove['column']]['seat'] = FALSE;
246
          }
247
          $real_seats--;
248
        }
249
      }
250
      
251
      else {
252
        //we need to add some
253
        while ($needed_seats > $real_seats) {
254
          $real_seats++;
255
          $blank = array_shift($blanks);
256
          $element['#value']['floors'][$blank['floor']]['rows'][$blank['row']]['columns'][$blank['column']]['seat'] = $real_seats;
257
        }
258
      }
259
    }
260
  }
261
262
  $plan = $element['#value'];
263
}
264
  $parents = $element['#parents'];
265
  $element['floors'] = array(
266
    '#prefix' => '<div id="as-wrap-'. $element['#id'] .'">',
267
    '#suffix' => '</div>'
268
  );
269
  if ($form_state['storage']['type']) {
270
    $total_seats = allocated_seating_total_seats($plan);
271
    if ($total_seats < $element['#seats']) {
272
      form_set_error(implode('][', $element['#parents']), t('The entered row and column combination is not sufficient to meet the required number of seats, please try again'));
273
    }
274
    switch ($form_state['storage']['type']) {
275
      case 'row':
276
        $floor = $form_state['storage']['floor'];
277
        $current_rows = $original_rows = count($plan['floors'][$floor]['rows']);
278
        $row_count = $plan['floors'][$floor]['row_count'];
279
        while ($current_rows < $row_count) {
280
          allocated_seating_plan_floor_add_row($plan, $floor);
281
          $current_rows++;
282
        }
283
        while ($current_rows > $row_count) {
284
          allocated_seating_plan_remove_row($plan, $floor);
285
          $current_rows--;
286
        }
287
        break;
288
      
289
      case 'column':
290
        $floor = $form_state['storage']['floor'];
291
        $current_cols = $original_cols = count($plan['floors'][$floor]['rows'][0]['columns']);
292
        $col_count = $plan['floors'][$floor]['col_count'];
293
        if ($col_count > 23) {
294
          form_set_error('', t('The seating designer does not support more than 23 columns.'));
295
          $col_count = 23;
296
        }
297
        while ($current_cols < $col_count) {
298
          allocated_seating_plan_floor_add_column($plan, $floor);
299
          $current_cols++;
300
        }
301
        while ($current_cols > $col_count) {
302
          allocated_seating_plan_remove_column($plan, $floor);
303
          $current_cols--;
304
        }
305
        break;
306
    }
307
    unset($form_state['storage']['type'], $form_state['storage']['floor']);
308
  }
309
  foreach ($plan['floors'] as $f => $floor) {
310
    $element['floors'][$f] = array(
311
      '#tree' => TRUE,
312
      '#parents' => array_merge($parents, array('floors', $f)),
313
      'title' => array(
314
        '#type'          => 'textfield',
315
        '#title'         => t('Floor title'),
316
        '#parents' => array_merge($parents, array('floors', $f, 'title')),
317
        '#default_value' => t('Floor !floor', array('!floor' => $f + 1)),
318
        '#size'          => 10,
319
        '#maxlength'     => 50,
320
        '#required'      => TRUE,
321
      ),
322
      'row_count' => array(
323
        '#type'          => 'textfield',
324
        '#title'         => t('Rows'),
325
        '#parents' => array_merge($parents, array('floors', $f, 'row_count')),
326
        '#default_value' => count($floor['rows']),
327
        '#size'          => 10,
328
        '#maxlength'     => 10,
329
        '#required'      => TRUE,
330
        '#ajax' => array(
331
          'path' => 'allocated_seating/ajax/row/'. $f + 1 .'/'. $element['#ajax_extra'] . implode('/', $parents),
332
          'wrapper' => 'as-wrap-'. $element['#id'],
333
          'event' => 'change',
334
          'method' => 'replace',
335
          'effect' => 'fade',
336
        ),
337
      ),
338
      'col_count' => array(
339
        '#type'          => 'textfield',
340
        '#title'         => t('Columns'),
341
        '#parents'       => array_merge($parents, array('floors', $f, 'col_count')),
342
        '#default_value' => count($floor['rows'][0]['columns']),
343
        '#size'          => 10,
344
        '#maxlength'     => 10,
345
        '#required'      => TRUE,
346
        '#ajax' => array(
347
          'event' => 'change',
348
          'path' => 'allocated_seating/ajax/column/'. $f + 1 .'/'. $element['#ajax_extra'] . implode('/', $parents),
349
          'wrapper' => 'as-wrap-'. $element['#id'],
350
          'method' => 'replace',
351
          'effect' => 'fade',
352
        ),
353
      ),
354
      'remove_floor' => array(
355
        '#type' => 'submit',
356
        '#value' => t('Remove floor '). ($f + 1),
357
        '#submit' => array('allocated_seating_design_remove_floor'),
358
        '#ajax' => array(
359
          'path' => 'allocated_seating/ajax/floor/'. $element['#ajax_extra'] . implode('/', $parents),
360
          'wrapper' => 'as-wrap-'. $element['#id'],
361
          'method' => 'replace',
362
          'effect' => 'fade',
363
        )
364
      ),
365
      'rows' => array(
366
        '#tree' => TRUE,
367
        '#parents' => array_merge($parents, array('floors', $f, 'rows')),
368
      )  
369
    );
370
    foreach ($floor['rows'] as $r => $row) {
371
      $element['floors'][$f]['rows'][$r] = array(
372
        '#tree' => TRUE,
373
        '#parents' => array_merge($parents, array('floors', $f, 'rows', $r)),
374
        'columns' => array(
375
          '#tree' => TRUE,
376
          '#parents' => array_merge($parents, array('floors', $f, 'rows', $r, 'columns')),
377
        )
378
      );
379
      foreach ($row['columns'] as $c => $column) {
380
        //add the seat string and value
381
        $element['floors'][$f]['rows'][$r]['columns'][$c]['drag'] = array(
382
          '#parents' => array_merge($parents, array('floors', $f, 'rows', $r, 'columns', $c, 'drag')),
383
          '#attributes' => array('class' => 'allocated-seating-seat'),
384
          '#type' => '#markup',
385
          '#value' => $column['seat'] ? $column['seat'] : '&nbsp;'
386
        );
387
        $element['floors'][$f]['rows'][$r]['columns'][$c]['seat'] = array(
388
          '#parents' => array_merge($parents, array('floors', $f, 'rows', $r, 'columns', $c, 'seat')),
389
          '#type' => 'hidden',
390
          '#value' => $column['seat']
391
        );
392
      }
393
    }
394
  }
395
  
396
  $element['add_floor_row_count'] = array(
397
    '#type'          => 'textfield',
398
    '#title'         => t('Rows'),
399
    '#default_value' => isset($form_state['post']['add_floor_row_count']) ? $form_state['post']['add_floor_row_count'] : 4,
400
    '#size'          => 10,
401
    '#maxlength'     => 10
402
  );
403
  
404
  $element['add_floor_col_count'] = array(
405
    '#type'          => 'textfield',
406
    '#title'         => t('Cols'),
407
    '#default_value' => isset($form_state['post']['add_floor_col_count']) ? $form_state['post']['add_floor_col_count'] : 10,
408
    '#size'          => 10,
409
    '#maxlength'     => 10
410
  );
411
  
412
  $element['add_floor_ticket_count'] = array(
413
    '#type'          => 'textfield',
414
    '#title'         => t('Tickets'),
415
    '#default_value' => 0,
416
    '#size'          => 10,
417
    '#maxlength'     => 10,
418
    '#description'   => t('Start with this many tickets on the floor')
419
  );
420
  
421
  $element['add_floor'] = array(
422
    '#type' => 'submit',
423
    '#value' => t('Add floor'),
424
    '#submit' => array('allocated_seating_design_add_floor'),
425
    '#executes_submit_callback' => true,
426
    '#ajax' => array(
427
      'path' => 'allocated_seating/ajax/floor/'. $element['#ajax_extra'] . implode('/', $parents),
428
      'callback' => 'allocated_seating_design_add_floor',
429
      'wrapper' => 'as-wrap-'. $element['#id'],
430
      'method' => 'replace',
431
      'effect' => 'fade',
432
    )
433
  );
434
  return $element;  
435
}
436
437
/**
438
 * Removes a floor from the design
439
*/
440
function allocated_seating_design_remove_floor($form, &$form_state) {
441
  $button = $form_state['clicked_button'];
442
  $field_parents = $button['#parents'];
443
  $floor = $field_parents[count($field_parents) - 2];
444
  $depth = count($field_parents) - 4;
445
  $field_name = $field_parents[$depth];
446
  if ($depth > 0) {
447
    //we have a tree arrangement here
448
    switch ($depth) {
449
      case 1:
450
        allocated_seating_plan_remove_floor($form_state['values'][$field_parents[0]][$field_name], $floor);
451
        break;
452
      case 2:
453
        allocated_seating_plan_remove_floor($form_state['values'][$field_parents[0]][$field_parents[1]][$field_name], $floor);
454
        break;
455
      case 3:
456
        allocated_seating_plan_remove_floor($form_state['values'][$field_parents[0]][$field_parents[1]][$field_parents[2]][$field_name], $floor);
457
        break;
458
      //that ought to be enough
459
    }
460
  }
461
  else {
462
    allocated_seating_plan_remove_floor($form_state['values'][$field_name], $floor);
463
  }
464
  unset($form_state['submit_handlers']);
465
  form_execute_handlers('submit', $form, $form_state);
466
  $form_state['rebuild'] = TRUE;
467
}
468
469
/**
470
 * Adds a floor to a design
471
*/
472
function allocated_seating_design_add_floor($form, &$form_state) {
473
474
  $button = $form_state['clicked_button'];
475
  $parents = $button['#array_parents'];
476
  $button_name = array_pop($parents);
477
  $field_name = array_pop($parents);
478
  $field_parents = $button['#parents'];
479
  $new_rows = $form_state['values']['add_floor_row_count'];
480
  $new_cols = $form_state['values']['add_floor_col_count'];
481
  $new_tickets = $form_state['values']['add_floor_ticket_count'];
482-
  echo 'asds';
482+
483-
  exit();
483+
484
    //we have a tree arrangement here
485
    switch (count($field_parents)) {
486
      case 2:
487
        //allocated_seating_plan_add_floor($form_state['values'][$field_parents[0]][$field_name], $new_rows, $new_cols, $new_tickets);
488
        break;
489
      case 3:
490
       // allocated_seating_plan_add_floor($form_state['values'][$field_parents[0]][$field_parents[1]][$field_name], $new_rows, $new_cols, $new_tickets);
491
        break;
492
      case 4:
493
       // allocated_seating_plan_add_floor($form_state['values'][$field_parents[0]][$field_parents[1]][$field_parents[2]][$field_name], $new_rows, $new_cols, $new_tickets);
494
        break;
495
      //that ought to be enough
496
    }
497
  }
498
  else {
499
    //allocated_seating_plan_add_floor($form_state['values'][$field_name], $new_rows, $new_cols, $new_tickets);
500
  }
501
  unset($form_state['submit_handlers']);
502
  form_execute_handlers('submit', $form, $form_state);
503
  $form_state['rebuild'] = TRUE;
504
}
505
506
/**
507
 * Default implementation of theme_allocated_seating_seat_select
508
*/
509
function theme_allocated_seating_seat_select($element) {
510
  jquery_ui_add(array('ui.sortable', 'ui.droppable', 'ui.tabs'));
511
  drupal_add_js(drupal_get_path('module', 'allocated_seating') .'/allocated_seating.js');
512
  drupal_add_css(drupal_get_path('module', 'allocated_seating') .'/allocated_seating.css');
513
  drupal_add_css(drupal_get_path('module', 'jquery_ui') . '/jquery.ui/themes/default/ui.all.css');
514
  $output = '<div id="allocated-seating-tabs" class="allocated-seating-seat-select"><ul>';
515
  $tabs = '';
516
  foreach (element_children($element['floors']) as $key) {
517
    $title = $element['floors'][$key]['title']['#value'];
518
    $output .= '<li><a href="#allocated-seating-tabs-'. $key .'">'. check_plain($title) .'</a></li>';
519
    $tabs .= '<div id="allocated-seating-tabs-'. $key .'">'.
520
      $element['floors'][$key]['title']['#value']
521
      . '<div class="floor-front cols-'. $element['floors'][$key]['#col_count'] .'">'. t('Front') .'</div>'
522
      .'<ul class="allocated-seating-seats no-drag cols-'. $element['floors'][$key]['#col_count'] .'">';
523
    foreach (element_children($element['floors'][$key]['rows']) as $row) {
524
      foreach (element_children($element['floors'][$key]['rows'][$row]['columns']) as $column) {
525
        $tabs .= '<li class="ui-state-highlight';
526
        if ($element['floors'][$key]['rows'][$row]['columns'][$column]['#type'] == 'checkbox') {
527
          $tabs .= '">'. theme('checkbox', $element['floors'][$key]['rows'][$row]['columns'][$column]);
528
        }
529
        else {
530
          $tabs .= ' not-available">&nbsp';
531
        }
532
        $tabs .=  '</li>';
533
      }
534
    }
535
    $tabs .= '</ul>'. $values .'<div class="clear"></div></div>';
536
  }
537
  $output .= '</ul>';
538
  $output .= $tabs;
539
  $output .= '</div>';
540
  return $output;
541
}
542
543
/**
544
 * Default implementation of theme_allocated_seating_seat_available
545
*/
546
function theme_allocated_seating_seat_available($plan, $not_available) {
547
  $blank = 1;
548
  $element['floors'] = array(
549
    '#tree' => FALSE, //we structure the data in a nest for theming but only want seat# => 1/0
550
    '#parents' => array('floors')
551
  );
552
  foreach ($plan['floors'] as $f => $floor) {
553
    $element['floors'][$f] = array(
554
      '#tree' => FALSE,
555
      '#col_count' => $floor['col_count'],
556
      'title' => array(
557
        '#value' => $floor['title']
558
      ),
559
      'rows' => array(
560
        '#tree' => FALSE,
561
      )  
562
    );
563
    foreach ($floor['rows'] as $r => $row) {
564
      $element['floors'][$f]['rows'][$r] = array(
565
        '#tree' => FALSE,
566
        'columns' => array(
567
          '#tree' => FALSE,
568
          '#parents' => array('floors', $f, 'rows', $r, 'columns'),
569
        )
570
      );
571
      foreach ($row['columns'] as $c => $column) {
572
        $state = 'available';
573
        if ($column['seat'] &&
574
            is_numeric($column['seat']) &&
575
            in_array($column['seat'], $not_available)) {
576
          $state = 'unavailable';
577
        }
578
        //add the seat field
579
        $element['floors'][$f]['rows'][$r]['columns'][$column['seat']] = array(
580
          '#value' => '<div class="allocated-seating-seat '. $state .'">'. $column['seat'] .'</div>',
581
          '#parents' => array('seats', $column['seat']),
582
        );
583
      }
584
    }
585
  }
586
  drupal_add_library('system', 'ui.sortable');
587
  drupal_add_library('system', 'ui.tabs');
588
  drupal_add_library('system', 'ui.droppable');
589
  //jquery_ui_add(array('ui.sortable', 'ui.droppable', 'ui.tabs'));
590
  drupal_add_js(drupal_get_path('module', 'allocated_seating') .'/allocated_seating.js');
591
  drupal_add_css(drupal_get_path('module', 'allocated_seating') .'/allocated_seating.css');
592
  drupal_add_css(drupal_get_path('module', 'jquery_ui') . '/jquery.ui/themes/default/ui.all.css');
593
  $output = '<div id="allocated-seating-tabs" class="allocated-seating-seat-select"><ul>';
594
  $tabs = '';
595
  foreach (element_children($element['floors']) as $key) {
596
    $title = $element['floors'][$key]['title']['#value'];
597
    $output .= '<li><a href="#allocated-seating-tabs-'. $key .'">'. check_plain($title) .'</a></li>';
598
    $tabs .= '<div id="allocated-seating-tabs-'. $key .'">'.
599
      $element['floors'][$key]['title']['#value']
600
      . '<div class="floor-front cols-'. $element['floors'][$key]['#col_count'] .'">'. t('Front') .'</div>'
601
      .'<ul class="allocated-seating-seats no-drag cols-'. $element['floors'][$key]['#col_count'] .'">';
602
    foreach (element_children($element['floors'][$key]['rows']) as $row) {
603
      foreach (element_children($element['floors'][$key]['rows'][$row]['columns']) as $column) {
604
        $tabs .= '<li class="ui-state-highlight">'.
605
          drupal_render($element['floors'][$key]['rows'][$row]['columns'][$column])
606
        .'</li>';
607
      }
608
    }
609
    $tabs .= '</ul>'. $values .'<div class="clear"></div></div>';
610
  }
611
  $output .= '</ul>';
612
  $output .= $tabs;
613
  $output .= '</div>';
614
  return $output;
615
}
616
617
/**
618
 * Default implementation of theme_allocated_seating_seat_design
619
*/
620
function theme_allocated_seating_seat_design($variable) {
621
  drupal_add_library('system', 'ui.sortable');
622
  drupal_add_library('system', 'ui.tabs');
623
  drupal_add_library('system', 'ui.droppable');
624
  $element = array_shift($variable);
625
626
  //jquery_ui_add(array('ui.sortable', 'ui.tabs', 'ui.droppable'));
627
  drupal_add_js(drupal_get_path('module', 'allocated_seating') .'/allocated_seating.js');
628
  drupal_add_css(drupal_get_path('module', 'allocated_seating') .'/allocated_seating.css');
629
  drupal_add_css(drupal_get_path('module', 'jquery_ui') . '/jquery.ui/themes/default/ui.all.css');
630
  $output = '<div id="as-wrap-'. $element['#id'] .'" class="as-wrap"><div id="allocated-seating-tabs" class="allocated-seating-seat-design"><ul>';
631
  $tabs = '';
632
  foreach (element_children($element['floors']) as $key) {
633
    $inputs = '';
634
    $title = $element['floors'][$key]['title']['#value'];
635
    $output .= '<li><a href="#allocated-seating-tabs-'. $key .'">'. check_plain($title) .'</a></li>';
636
    $tabs .= '<div id="allocated-seating-tabs-'. $key .'" class="floor-details">'.
637
      '<div class="floor-item">'.
638
      theme('form_element_label', $element['floors'][$key]['title']).
639
      theme('textfield', $element['floors'][$key]['title']) .
640
      '</div><div class="floor-item">'.
641
      theme('form_element_label', $element['floors'][$key]['row_count']).
642
      theme('textfield', $element['floors'][$key]['row_count']) .
643
      '</div><div class="floor-item">'.
644
      theme('form_element_label', $element['floors'][$key]['col_count']).
645
      theme('textfield', $element['floors'][$key]['col_count']).
646
      '</div>'
647
      . '<div class="floor-front cols-'. $element['floors'][$key]['col_count']['#value'] .'">'. t('Front') .'</div>'
648
      .'<ul class="allocated-seating-seats connectedSortable ui-helper-reset cols-'. $element['floors'][$key]['col_count']['#value'] .'">';
649
    foreach (element_children($element['floors'][$key]['rows']) as $row) {
650
      foreach (element_children($element['floors'][$key]['rows'][$row]['columns']) as $column) {
651
        $tabs .= '<li class="ui-state-highlight" rel="'. $element['floors'][$key]['rows'][$row]['columns'][$column]['seat']['#value'] .'">'.
652
                    $element['floors'][$key]['rows'][$row]['columns'][$column]['drag']['#value']
653
                .'</li>';
654
        $inputs .= theme('hidden', $element['floors'][$key]['rows'][$row]['columns'][$column]['seat']);
655
      }
656
    }
657
    $tabs .= $inputs .'</ul>'. $values .'<div class="clear"></div>'.
658
      drupal_render($element['floors'][$key]['remove_floor'])
659
      .'</div>';
660
  }
661
  $output .= '</ul>';
662
  $output .= $tabs;
663
  $output .= '</div><div class="allocated-seating-design-add-floor"><fieldset><legend>'. t('Add a floor') .'</legend>'.
664
            t('Add a new floor with this many rows/columns').
665
            drupal_render($element['add_floor_row_count']).
666
            drupal_render($element['add_floor_col_count']).
667
            drupal_render($element['add_floor_ticket_count']).
668
            drupal_render($element['add_floor'])
669
          .'</fieldset></div>';
670
  if (!empty($element['#description'])) {
671
    $output .= ' <div class="description as-description">'. $element['#description'] ."</div>\n";
672
  }       
673
  $output .= '</div><div class="clear"></div>';
674
  return $output;
675
}
676
677
/**
678
 * Validation handler for seat selection
679
*/
680
function allocated_seating_seat_select_validate($element, &$form_state) {
681
  $seats = array_sum($form_state['values']['seats']);
682
  if ($element['#required_seats'] &&
683
      $element['#required_seats'] != $seats) {
684
    form_error($element, format_plural($element['#required_seats'],
685
                                     'Please choose 1 seat',
686
                                     'Please choose @count seats'));
687
  }
688
}
689
690
/**
691
 * Call callback handler.
692
 * 
693
 */
694
function allocated_seating_ajax() {
695
  module_load_include('inc', 'node', 'node.pages');
696
  //get args
697
698
  $elements = func_get_args();
699
  $type = array_shift($elements);
700
  if ($type == 'row' || $type == 'column') {
701
    $floor = array_shift($elements);
702
  }
703
704
  
705
  //we set submitted as TRUE so prevent _form_builder_ie_cleanup() from triggering
706
  //submit on ajax that does not involve a button
707
  $form_state = array('storage' => NULL, 'submitted' => TRUE);
708
  $form_build_id = $_POST['form_build_id'];
709
  $form = form_get_cache($form_build_id, $form_state);
710
  if (isset($_POST['_triggering_element_name'])) {
711
712
	if($_POST['_triggering_element_name'] == 'op' && $_POST['_triggering_element_value'] == 'Add floor') {
713
		$form_state['submit_handlers'] = array('allocated_seating_design_add_floor');
714
	}
715
  } 
716
717
  unset($form_state['storage']['type']); //don't redo the cached action
718
  //remove validation (thanks ajax_helper!)
719
  if (!isset($_POST['op'])) {
720
    // For the defaults 
721
    $form['#validate'] = NULL;
722
    $form['#submit'] = NULL;
723
    // For customly set #validate and #submit handlers.
724
    $form_state['submit_handlers'] = array();
725
    $form_state['validate_handlers'] = array();
726
  }
727
  $form_id = $form['#form_id'];
728
  $form['#post'] = $_POST;
729
  $form['#redirect'] = FALSE;
730
  $form['#programmed'] = FALSE;
731
  $form_state['post'] = $_POST;
732
733
  drupal_process_form($form_id, $form, $form_state);
734
735
  $form_state['storage']['type'] = $type;
736
  $form_state['storage']['floor'] = $floor;
737
  if ($type == 'floor') {
738
    $form_state['storage']['add_floor_row_count'] = $form_state['values']['add_floor_row_count'];
739
    $form_state['storage']['add_floor_col_count'] = $form_state['values']['add_floor_col_count'];
740
  }
741
742
  $form = drupal_rebuild_form($form_id, $form_state,  $form );
743
  foreach ($elements as $element) {
744
    $form = $form[$element];
745
  }
746
  if (!$form) {
747
    watchdog('allocated seating', 'Call method was called with elements not found in resultant form', array(), WATCHDOG_ERROR);
748
    $form = array(
749
      'error' => array(
750
        '#value' => t('An error occured while processing your request, please try again. If the problem persists, please contact the site administrator')
751
      )
752
    );
753
  }
754
  unset($form['#prefix'], $form['#suffix']); // Prevent duplicate wrappers.
755
  $javascript = drupal_add_js(NULL, NULL, 'header');
756
  // Loop through the JS settings and find the settings needed for our buttons.
757
758
759
  $new_ajax_settings = array();
760
  if (isset($javascript['settings'])) {
761
    foreach ($javascript['settings'] as $settings) {
762
      if (isset($settings['ajax'])) {
763
        foreach ($settings['ajax'] as $id => $ajax_settings) {
764
            $new_ajax_settings[$id] = $ajax_settings;
765
        }
766
      }
767
    }
768
  }
769
770
  // Add the Call settings needed for our new elements.
771
  if (!empty($new_ajax_settings)) {
772
    $output = '<script type="text/javascript">jQuery.extend(Drupal.settings.Ajax, '. drupal_to_js($new_ajax_settings) .');</script>';
773
  }
774
775
  return array(array(
776
    'status'   => TRUE,
777
    'data'     => theme('status_messages') . $output . drupal_render($form),
778
    'settings' => call_user_func_array('array_merge_recursive', $javascript['setting']),
779
    'command' => 'syncSeating'
780
  ));
781
}
782
783
/**
784
 * Utility to remove a floor from the plan
785
 * @param $plan array the plan
786
*/
787
function allocated_seating_plan_remove_floor(&$plan, $floor) {
788
  if (!isset($plan['floors'][$floor])) {
789
    return;
790
  }
791
  foreach ($plan['floors'][$floor]['rows'] as $row) {
792
    foreach ($row['columns'] as $col) {
793
      if ((int)$col['seat'] > 0) {
794
        form_set_error('', t('You cannot remove this floor, it still contains seats, please move them to another floor first.'));
795
        return;
796
      }
797
    }
798
  }
799
  unset($plan['floors'][$floor]);
800
}
801
802
803
/**
804
 * Utility to remove a col from the plan
805
 * @param $plan array the plan
806
*/
807
function allocated_seating_plan_remove_column(&$plan, $floor) {
808
  if (!isset($plan['floors'][$floor])) {
809
    return;
810
  }
811
  $remove_col = count($plan['floors'][$floor]['rows'][0]['columns']) - 1;
812
  foreach ($plan['floors'][$floor]['rows'] as $row) {
813
    $col = $row['columns'][$remove_col];
814
    if ((int)$col['seat'] > 0) {
815
      form_set_error('', t('You cannot remove the last column from this floor, it still contains seats, please move them to another floor or column first.'));
816
      return;
817
    }
818
  }
819
  foreach ($plan['floors'][$floor]['rows'] as $key => $row) {
820
    unset($plan['floors'][$floor]['rows'][$key]['columns'][$remove_col]);
821
  }
822
}
823
824
/**
825
 * Utility to remove a row from the plan
826
 * @param $plan array the plan
827
*/
828
function allocated_seating_plan_remove_row(&$plan, $floor) {
829
  if (!isset($plan['floors'][$floor])) {
830
    return;
831
  }
832
  $remove_row = count($plan['floors'][$floor]['rows']) - 1;
833
  foreach ($plan['floors'][$floor]['rows'][$remove_row]['columns'] as $col) {
834
    if ((int)$col['seat'] > 0) {
835
      form_set_error('', t('You cannot remove the last row from this floor, it still contains seats, please move them to another floor or row first.'));
836
      return;
837
    }
838
  }
839
  unset($plan['floors'][$floor]['rows'][$remove_row]);
840
}
841
842
/**
843
 * Utility to add a floor to a plan
844
 * @param $plan array the plan
845
*/
846
function allocated_seating_plan_add_floor(&$element, &$post) {
847
848
  $plan = &$element['#value'];
849
  $rows = $plan['add_floor_row_count'];
850
  $cols = $plan['add_floor_col_count'];
851
  $tickets = $plan['add_floor_ticket_count'];
852
  $available_tickets = array();
853
  if ($tickets) {
854
    if ($tickets > ($rows * $cols)) {
855
      $tickets = $rows * $cols;
856
      drupal_set_message(t('You cannot move more than !tix seats to the new floor', array('!tix' => ($rows * $cols))));
857
    }
858
    $map = allocated_seating_get_map($plan);
859
    $seat = count($available_tickets);
860
    $seats = $map['seats'];
861
    $seat_numbers = array_keys($seats);
862
    asort($seat_numbers);
863
    while ($seat < $tickets) {
864
      $seat++;
865
      $new_seat = array_pop($seat_numbers);
866
      $remove = $seats[$new_seat];
867
      $available_tickets[] = $new_seat;
868
      $plan['floors'][$remove['floor']]['rows'][$remove['row']]['columns'][$remove['column']]['seat'] = FALSE;
869
    }
870
  }
871
  $floor = array(
872
    'title' => t('Floor !floor', array('!floor' => count($plan['floors']) + 1)),
873
    'rows' => array()
874
  );
875
  $row = 0;
876
  $s = 1;
877
  while ($row < $rows) {
878
    $col = 0;
879
    $floor['rows'][$row] = array('columns' => array()); //add the rows
880
    while ($col < $cols) {
881
      if (count($available_tickets) > 0) {
882
        $seat = array_pop($available_tickets);
883
      }
884
      else {
885
        $seat = FALSE;
886
      }
887
      $floor['rows'][$row]['columns'][] = array('seat' => $seat); //add the seat as a blank or a number
888
      $col++;
889
    }
890
    $row++;
891
  }
892
  $plan['floors'][] = $floor;
893
}
894
895
/**
896
 * Utility to add row to a floor of a plan
897
 * @param $plan array the plan
898
 * @param $floor int the floor delta
899
*/
900
function allocated_seating_plan_floor_add_row(&$plan, $floor) {
901
  $cols = count($plan['floors'][$floor]['rows'][0]['columns']);
902
  $rows = count($plan['floors'][$floor]['rows']);
903
  $col = 0;
904
  $row = array('columns' => array()); //create the row
905
  while ($col < $cols) {
906
    $row['columns'][] = array('seat' => FALSE); //add the seat as a blank
907
    $col++;
908
  }
909
  $plan['floors'][$floor]['rows'][] = $row;
910
}
911
912
/**
913
 * Utility to add column to a floor of a plan
914
 * @param $plan array the plan
915
 * @param $floor int the floor delta
916
*/
917
function allocated_seating_plan_floor_add_column(&$plan, $floor) {
918
  $rows = count($plan['floors'][$floor]['rows']);
919
  $row = 0;
920
  while ($row < $rows) {
921
    $plan['floors'][$floor]['rows'][$row]['columns'][] = array('seat' => FALSE);
922
    $row++;
923
  }
924
}
925
926
/**
927
 * Utility to setup required js files etc
928
*/
929
function allocated_seating_setup() {
930
  drupal_add_library('system', 'ui.sortable');
931
  drupal_add_library('system', 'ui.tabs');
932
  drupal_add_library('system', 'ui.droppable');
933
  //jquery_ui_add(array('ui.sortable', 'ui.tabs', 'ui.droppable'));
934
  drupal_add_js(drupal_get_path('module', 'allocated_seating') .'/allocated_seating.js');
935
  drupal_add_css(drupal_get_path('module', 'allocated_seating') .'/allocated_seating.css');
936
}
937
938
/**
939
 * Util to fetch number of rows and columns (seats) submitted in the plan
940
 * @param $plan array seating plan as submitted in $element['#value']
941
*/
942
function allocated_seating_total_seats($plan) {
943
  $seats = 0;
944
  foreach ($plan['floors'] as $floor) {
945
    $rows = $floor['row_count'];
946
    $cols = $floor['col_count'];
947
    $seats += ($rows * $cols);
948
  }
949
  return $seats;
950
}
951
952
/**
953
 * Util to fetch number of rows and columns (seats) submitted in the plan
954
 * @param $plan array seating plan as submitted in $element['#value']
955
*/
956
function allocated_seating_plan_seats($plan) {
957
  $seats = 0;
958
  foreach ($plan['floors'] as $floor) {
959
    $rows = count($floor['rows']);
960
    $cols = count($floor['rows'][0]['columns']);
961
    $seats += ($rows * $cols);
962
  }
963
  return $seats;
964
}
965
966
/**
967
 * Util to fetch number of real seats (non blank) in the plan
968
 * @param $plan array seating plan as submitted in $element['#value']
969
*/
970
function allocated_seating_real_seats($plan) {
971
  $seats = 0;
972
  foreach ($plan['floors'] as $floor) {
973
    foreach ($floor['rows'] as $row) {
974
      foreach ($row['columns'] as $column) {
975
        if ((int)$column['seat'] > 0) {
976
          $seats++;
977
        }
978
      }
979
    }
980
  }
981
  return $seats;
982
}
983
984
/**
985
 * Util to fetch reveresed map keyed by seat
986
 * @param $plan array seating plan
987
 * @return array with two members as follows
988
 *  seats => array keyed by seat # with array or floor, row and column members
989
 *  blanks => same but for blanks
990
*/
991
function allocated_seating_get_map($plan) {
992
  $map = $blanks = array();
993
  foreach ($plan['floors'] as $fid => $floor) {
994
    foreach ($floor['rows'] as $rid => $row) {
995
      foreach ($row['columns'] as $cid => $column) {
996
        if ((int)$column['seat'] > 0) {
997
          $map[$column['seat']] = array('row' => $rid, 'column' => $cid, 'floor' => $fid);
998
        }
999
        else {
1000
          $blanks[] = array('row' => $rid, 'column' => $cid, 'floor' => $fid);
1001
        }
1002
      }
1003
    }
1004
  }
1005
  return array('seats' => $map, 'blanks' => $blanks);
1006
}