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' => ' ' | |
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'] : ' ' | |
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"> '; | |
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 | } |