ILIAS  Release_4_4_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilCalendarWeekGUI.php
Go to the documentation of this file.
1 <?php
2 /*
3  +-----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +-----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2006 ILIAS open source, University of Cologne |
7  | |
8  | This program is free software; you can redistribute it and/or |
9  | modify it under the terms of the GNU General Public License |
10  | as published by the Free Software Foundation; either version 2 |
11  | of the License, or (at your option) any later version. |
12  | |
13  | This program is distributed in the hope that it will be useful, |
14  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16  | GNU General Public License for more details. |
17  | |
18  | You should have received a copy of the GNU General Public License |
19  | along with this program; if not, write to the Free Software |
20  | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21  +-----------------------------------------------------------------------------+
22 */
23 
34 include_once('Services/Calendar/classes/class.ilDate.php');
35 include_once('Services/Calendar/classes/class.ilCalendarHeaderNavigationGUI.php');
36 include_once('Services/Calendar/classes/class.ilCalendarUserSettings.php');
37 include_once('Services/Calendar/classes/class.ilCalendarAppointmentColors.php');
38 
39 
40 
42 {
43  protected $num_appointments = 1;
44  protected $seed = null;
45  protected $user_settings = null;
46  protected $weekdays = array();
47 
48  protected $lng;
49  protected $ctrl;
50  protected $tabs_gui;
51  protected $tpl;
52 
53  protected $timezone = 'UTC';
54 
62  public function __construct(ilDate $seed_date)
63  {
64  global $ilCtrl, $lng, $ilUser,$ilTabs,$tpl;
65 
66  $this->seed = $seed_date;
67  $this->seed_info = $this->seed->get(IL_CAL_FKT_GETDATE,'','UTC');
68 
69  $this->tpl = $tpl;
70  $this->lng = $lng;
71  $this->ctrl = $ilCtrl;
72  $this->tabs_gui = $ilTabs;
73 
74  $this->user_settings = ilCalendarUserSettings::_getInstanceByUserId($ilUser->getId());
75  $this->app_colors = new ilCalendarAppointmentColors($ilUser->getId());
76 
77  $this->timezone = $ilUser->getTimeZone();
78  }
79 
86  public function executeCommand()
87  {
88  global $ilCtrl,$tpl;
89 
90  $this->ctrl->saveParameter($this,'seed');
91 
92 
93  $next_class = $ilCtrl->getNextClass();
94  switch($next_class)
95  {
96  case 'ilcalendarappointmentgui':
97  $this->ctrl->setReturn($this,'');
98  $this->tabs_gui->setSubTabActive($_SESSION['cal_last_tab']);
99 
100  // initial date for new calendar appointments
101  $idate = new ilDate($_REQUEST['idate'], IL_CAL_DATE);
102 
103  include_once('./Services/Calendar/classes/class.ilCalendarAppointmentGUI.php');
104  $app = new ilCalendarAppointmentGUI($this->seed,$idate,(int) $_GET['app_id']);
105  $this->ctrl->forwardCommand($app);
106  break;
107 
108  default:
109  $time = microtime(true);
110  $cmd = $this->ctrl->getCmd("show");
111  $this->$cmd();
112  $tpl->setContent($this->tpl->get());
113  #echo "Zeit: ".(microtime(true) - $time);
114  break;
115  }
116 
117  return true;
118  }
119 
126  public function show()
127  {
128  global $ilUser, $lng;
129 
130 
131  // config
132  $raster = 15;
133  if($this->user_settings->getDayStart())
134  {
135  // push starting point to last "slot" of hour BEFORE morning aggregation
136  $morning_aggr = ($this->user_settings->getDayStart()-1)*60+(60-$raster);
137  }
138  else
139  {
140  $morning_aggr = 0;
141  }
142  $evening_aggr = $this->user_settings->getDayEnd()*60;
143 
144 
145  $this->tpl = new ilTemplate('tpl.week_view.html',true,true,'Services/Calendar');
146 
147  include_once('./Services/YUI/classes/class.ilYuiUtil.php');
150 
151 
152  $navigation = new ilCalendarHeaderNavigationGUI($this,$this->seed,ilDateTime::WEEK);
153  $this->tpl->setVariable('NAVIGATION',$navigation->getHTML());
154 
155  if(isset($_GET["bkid"]))
156  {
157  $user_id = $_GET["bkid"];
158  $disable_empty = true;
159  $no_add = true;
160  }
161  elseif($ilUser->getId() == ANONYMOUS_USER_ID)
162  {
163  $user_id = $ilUser->getId();
164  $disable_empty = false;
165  $no_add = true;
166  }
167  else
168  {
169  $user_id = $ilUser->getId();
170  $disable_empty = false;
171  $no_add = false;
172  }
173  include_once('Services/Calendar/classes/class.ilCalendarSchedule.php');
174  $this->scheduler = new ilCalendarSchedule($this->seed,ilCalendarSchedule::TYPE_WEEK,$user_id,$disable_empty);
175  $this->scheduler->addSubitemCalendars(true);
176  $this->scheduler->calculate();
177 
178  $counter = 0;
179  $hours = null;
180  $all_fullday = array();
181  foreach(ilCalendarUtil::_buildWeekDayList($this->seed,$this->user_settings->getWeekStart())->get() as $date)
182  {
183  $daily_apps = $this->scheduler->getByDay($date,$this->timezone);
184  $hours = $this->parseHourInfo($daily_apps,$date,$counter,$hours,
185  $morning_aggr,
186  $evening_aggr,
187  $raster
188  );
189  $this->weekdays[] = $date;
190 
191  $num_apps[$date->get(IL_CAL_DATE)] = count($daily_apps);
192 
193  $all_fullday[] = $daily_apps;
194  $counter++;
195  }
196 
197  $colspans = $this->calculateColspans($hours);
198 
199  include_once('Services/Calendar/classes/class.ilCalendarSettings.php');
200  $settings = ilCalendarSettings::_getInstance();
201 
202  // Table header
203  $counter = 0;
204  foreach(ilCalendarUtil::_buildWeekDayList($this->seed,$this->user_settings->getWeekStart())->get() as $date)
205  {
206  $date_info = $date->get(IL_CAL_FKT_GETDATE,'','UTC');
207  $this->ctrl->setParameterByClass('ilcalendarappointmentgui','seed',$date->get(IL_CAL_DATE));
208  $this->ctrl->setParameterByClass('ilcalendarappointmentgui','idate',$date->get(IL_CAL_DATE));
209  $this->ctrl->setParameterByClass('ilcalendardaygui','seed',$date->get(IL_CAL_DATE));
210 
211  if(!$no_add)
212  {
213  if ($settings->getEnableGroupMilestones())
214  {
215  $this->tpl->setCurrentBlock("new_ms");
216  $this->tpl->setVariable('H_NEW_MS_SRC', ilUtil::getImagePath('ms_add.png'));
217  $this->tpl->setVariable('H_NEW_MS_ALT', $this->lng->txt('cal_new_ms'));
218  $this->tpl->setVariable('NEW_MS_LINK', $this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui','addMilestone'));
219  $this->tpl->parseCurrentBlock();
220  }
221 
222 
223  $this->tpl->setCurrentBlock("new_app");
224  $this->tpl->setVariable('NEW_APP_LINK',$this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui','add'));
225  $this->ctrl->clearParametersByClass('ilcalendarappointmentgui');
226  $this->tpl->setVariable('NEW_APP_SRC',ilUtil::getImagePath('date_add.png'));
227  $this->tpl->setVariable('NEW_APP_ALT',$this->lng->txt('cal_new_app'));
228  $this->tpl->parseCurrentBlock();
229  }
230 
231  $dayname = ilCalendarUtil::_numericDayToString($date->get(IL_CAL_FKT_DATE,'w'),true);
232  $daydate = $date_info['mday'].' '.ilCalendarUtil::_numericMonthToString($date_info['mon'],false);
233 
234  if(!$disable_empty || $num_apps[$date->get(IL_CAL_DATE)] > 0)
235  {
236  $link = $this->ctrl->getLinkTargetByClass('ilcalendardaygui','');
237  $this->ctrl->clearParametersByClass('ilcalendardaygui');
238 
239  $this->tpl->setCurrentBlock("day_view1_link");
240  $this->tpl->setVariable('HEADER_DATE',$daydate);
241  $this->tpl->setVariable('DAY_VIEW_LINK',$link);
242  $this->tpl->parseCurrentBlock();
243 
244  $this->tpl->setCurrentBlock("day_view2_link");
245  $this->tpl->setVariable('DAYNAME',$dayname);
246  $this->tpl->setVariable('DAY_VIEW_LINK',$link);
247  $this->tpl->parseCurrentBlock();
248  }
249  else
250  {
251  $this->tpl->setCurrentBlock("day_view1_no_link");
252  $this->tpl->setVariable('HEADER_DATE',$daydate);
253  $this->tpl->parseCurrentBlock();
254 
255  $this->tpl->setCurrentBlock("day_view2_no_link");
256  $this->tpl->setVariable('DAYNAME',$dayname);
257  $this->tpl->parseCurrentBlock();
258  }
259 
260  $this->tpl->setCurrentBlock('day_header_row');
261  $this->tpl->setVariable('DAY_COLSPAN',max($colspans[$counter],1));
262  $this->tpl->parseCurrentBlock();
263 
264  $counter++;
265  }
266 
267  // show fullday events
268  $counter = 0;
269  foreach($all_fullday as $daily_apps)
270  {
271  foreach($daily_apps as $event)
272  {
273  if($event['fullday'])
274  {
275  $this->showFulldayAppointment($event);
276  }
277  }
278  $this->tpl->setCurrentBlock('f_day_row');
279  $this->tpl->setVariable('COLSPAN',max($colspans[$counter],1));
280  $this->tpl->parseCurrentBlock();
281  $counter++;
282  }
283  $this->tpl->setCurrentBlock('fullday_apps');
284  $this->tpl->setVariable('TXT_F_DAY', $lng->txt("cal_all_day"));
285  $this->tpl->parseCurrentBlock();
286 
287  $new_link_counter = 0;
288  foreach($hours as $num_hour => $hours_per_day)
289  {
290  $first = true;
291  foreach($hours_per_day as $num_day => $hour)
292  {
293  if($first)
294  {
295  if(!($num_hour%60) || ($num_hour == $morning_aggr && $morning_aggr) ||
296  ($num_hour == $evening_aggr && $evening_aggr))
297  {
298  $first = false;
299 
300  // aggregation rows
301  if(($num_hour == $morning_aggr && $morning_aggr) ||
302  ($num_hour == $evening_aggr && $evening_aggr))
303  {
304  $this->tpl->setVariable('TIME_ROWSPAN', 1);
305  }
306  // rastered hour
307  else
308  {
309  $this->tpl->setVariable('TIME_ROWSPAN', 60/$raster);
310  }
311 
312  $this->tpl->setCurrentBlock('time_txt');
313 
314  $this->tpl->setVariable('TIME',$hour['txt']);
315  $this->tpl->parseCurrentBlock();
316  }
317  }
318 
319  foreach($hour['apps_start'] as $app)
320  {
321  $this->showAppointment($app);
322  }
323 
324  // screen reader: appointments are divs, now output cell
325  if ($ilUser->prefs["screen_reader_optimization"])
326  {
327  $this->tpl->setCurrentBlock('scrd_day_cell');
328  $this->tpl->setVariable('TD_CLASS','calstd');
329  $this->tpl->parseCurrentBlock();
330  }
331 
332 
333  #echo "NUMDAY: ".$num_day;
334  #echo "COLAPANS: ".max($colspans[$num_day],1).'<br />';
335  $num_apps = $hour['apps_num'];
336  $colspan = max($colspans[$num_day],1);
337 
338 
339  // Show new apointment link
340  if(!$hour['apps_num'] && !$ilUser->prefs["screen_reader_optimization"] && !$no_add)
341  {
342  $this->tpl->setCurrentBlock('new_app_link');
343  $this->ctrl->setParameterByClass('ilcalendarappointmentgui','idate',$this->weekdays[$num_day]->get(IL_CAL_DATE));
344  $this->ctrl->setParameterByClass('ilcalendarappointmentgui','seed',$this->seed->get(IL_CAL_DATE));
345  $this->ctrl->setParameterByClass('ilcalendarappointmentgui','hour',floor($num_hour/60));
346  $this->tpl->setVariable('DAY_NEW_APP_LINK',$this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui','add'));
347  $this->ctrl->clearParametersByClass('ilcalendarappointmentgui');
348 
349  $this->tpl->setVariable('DAY_NEW_APP_SRC',ilUtil::getImagePath('date_add.png'));
350  $this->tpl->setVariable('DAY_NEW_APP_ALT',$this->lng->txt('cal_new_app'));
351  $this->tpl->setVariable('DAY_NEW_ID',++$new_link_counter);
352  $this->tpl->parseCurrentBlock();
353  }
354 
355  for($i = $colspan;$i > $hour['apps_num'];$i--)
356  {
357  if ($ilUser->prefs["screen_reader_optimization"])
358  {
359  continue;
360  }
361  $this->tpl->setCurrentBlock('day_cell');
362 
363  // last "slot" of hour needs border
364  $empty_border = '';
365  if($num_hour%60 == 60-$raster ||
366  ($num_hour == $morning_aggr && $morning_aggr) ||
367  ($num_hour == $evening_aggr && $evening_aggr))
368  {
369  $empty_border = ' calempty_border';
370  }
371 
372  if($i == ($hour['apps_num'] + 1))
373  {
374  $this->tpl->setVariable('TD_CLASS','calempty calrightborder'.$empty_border);
375  #$this->tpl->setVariable('TD_STYLE',$add_style);
376  }
377  else
378  {
379  $this->tpl->setVariable('TD_CLASS','calempty'.$empty_border);
380  #$this->tpl->setVariable('TD_STYLE',$add_style);
381  }
382 
383  if(!$hour['apps_num'])
384  {
385  $this->tpl->setVariable('DAY_ID',$new_link_counter);
386  }
387  $this->tpl->setVariable('TD_ROWSPAN',1);
388  $this->tpl->parseCurrentBlock();
389  }
390  }
391 
392  $this->tpl->touchBlock('time_row');
393  }
394 
395  $this->tpl->setVariable("TXT_TIME", $lng->txt("time"));
396  }
397 
405  protected function showFulldayAppointment($a_app)
406  {
407  $this->tpl->setCurrentBlock('panel_code');
408  $this->tpl->setVariable('NUM',$this->num_appointments);
409  $this->tpl->parseCurrentBlock();
410 
411  // milestone icon
412  if ($a_app['event']->isMilestone())
413  {
414  $this->tpl->setCurrentBlock('fullday_ms_icon');
415  $this->tpl->setVariable('ALT_FD_MS', $this->lng->txt("cal_milestone"));
416  $this->tpl->setVariable('SRC_FD_MS', ilUtil::getImagePath("icon_ms_s.png"));
417  $this->tpl->parseCurrentBlock();
418  }
419 
420  $this->tpl->setCurrentBlock('fullday_app');
421 
422  include_once('./Services/Calendar/classes/class.ilCalendarAppointmentPanelGUI.php');
423  $this->tpl->setVariable('PANEL_F_DAY_DATA',ilCalendarAppointmentPanelGUI::_getInstance($this->seed)->getHTML($a_app));
424  $this->tpl->setVariable('F_DAY_ID',$this->num_appointments);
425 
426  $compl = ($a_app['event']->isMilestone() && $a_app['event']->getCompletion() > 0)
427  ? " (".$a_app['event']->getCompletion()."%)"
428  : "";
429 
430  $this->tpl->setVariable('F_APP_TITLE',$a_app['event']->getPresentationTitle().$compl);
431 
432  $color = $this->app_colors->getColorByAppointment($a_app['event']->getEntryId());
433  $this->tpl->setVariable('F_APP_BGCOLOR',$color);
434  $this->tpl->setVariable('F_APP_FONTCOLOR',ilCalendarUtil::calculateFontColor($color));
435 
436  $this->ctrl->clearParametersByClass('ilcalendarappointmentgui');
437  $this->ctrl->setParameterByClass('ilcalendarappointmentgui','app_id',$a_app['event']->getEntryId());
438  $this->tpl->setVariable('F_APP_EDIT_LINK',$this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui','edit'));
439 
440  $this->tpl->parseCurrentBlock();
441 
442  $this->num_appointments++;
443  }
444 
451  protected function showAppointment($a_app)
452  {
453  global $ilUser;
454 
455  $this->tpl->setCurrentBlock('panel_code');
456  $this->tpl->setVariable('NUM',$this->num_appointments);
457  $this->tpl->parseCurrentBlock();
458 
459  if (!$ilUser->prefs["screen_reader_optimization"])
460  {
461  $this->tpl->setCurrentBLock('not_empty');
462  }
463  else
464  {
465  $this->tpl->setCurrentBLock('scrd_not_empty');
466  }
467 
468  include_once('./Services/Calendar/classes/class.ilCalendarAppointmentPanelGUI.php');
469  $this->tpl->setVariable('PANEL_DATA',ilCalendarAppointmentPanelGUI::_getInstance($this->seed)->getHTML($a_app));
470 
471  $this->ctrl->clearParametersByClass('ilcalendarappointmentgui');
472  $this->ctrl->setParameterByClass('ilcalendarappointmentgui','app_id',$a_app['event']->getEntryId());
473  $this->tpl->setVariable('APP_EDIT_LINK',$this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui','edit'));
474 
475  $color = $this->app_colors->getColorByAppointment($a_app['event']->getEntryId());
476  $style = 'background-color: '.$color.';';
477  $style .= ('color:'.ilCalendarUtil::calculateFontColor($color));
478  $td_style = $style;
479 
480 
481  if($a_app['event']->isFullDay())
482  {
483  $title = $a_app['event']->getPresentationTitle();
484  }
485  else
486  {
487  switch($this->user_settings->getTimeFormat())
488  {
490  $title = $a_app['event']->getStart()->get(IL_CAL_FKT_DATE,'H:i',$this->timezone);
491  break;
492 
494  $title = $a_app['event']->getStart()->get(IL_CAL_FKT_DATE,'h:ia',$this->timezone);
495  break;
496  }
497  // add end time for screen readers
498  if ($ilUser->prefs["screen_reader_optimization"])
499  {
500  switch($this->user_settings->getTimeFormat())
501  {
503  $title.= "-".$a_app['event']->getEnd()->get(IL_CAL_FKT_DATE,'H:i',$this->timezone);
504  break;
505 
507  $title.= "-".$a_app['event']->getEnd()->get(IL_CAL_FKT_DATE,'h:ia',$this->timezone);
508  break;
509  }
510  }
511 
512  $title .= (' '.$a_app['event']->getPresentationTitle());
513  $td_style .= $a_app['event']->getPresentationStyle();
514  }
515 
516  $this->tpl->setVariable('APP_TITLE',$title);
517  $this->tpl->setVariable('LINK_NUM',$this->num_appointments);
518 
519  $this->tpl->setVariable('LINK_STYLE',$style);
520 
521 
522  if (!$ilUser->prefs["screen_reader_optimization"])
523  {
524  // provide table cell attributes
525  $this->tpl->parseCurrentBlock();
526 
527  $this->tpl->setCurrentBlock('day_cell');
528 
529  $this->tpl->setVariable('DAY_CELL_NUM',$this->num_appointments);
530  $this->tpl->setVariable('TD_ROWSPAN',$a_app['rowspan']);
531  $this->tpl->setVariable('TD_STYLE',$td_style);
532  $this->tpl->setVariable('TD_CLASS','calevent');
533 
534  $this->tpl->parseCurrentBlock();
535  }
536  else
537  {
538  // screen reader: work on div attributes
539  $this->tpl->setVariable('DIV_STYLE',$style);
540  $this->tpl->parseCurrentBlock();
541  }
542 
543  $this->num_appointments++;
544 
545  }
546 
547 
548 
555  protected function parseHourInfo($daily_apps,$date,$num_day,$hours = null,
556  $morning_aggr, $evening_aggr, $raster)
557  {
558  global $ilUser;
559 
560  for($i = $morning_aggr;$i <= $evening_aggr;$i+=$raster)
561  {
562  $hours[$i][$num_day]['apps_start'] = array();
563  $hours[$i][$num_day]['apps_num'] = 0;
564  switch($this->user_settings->getTimeFormat())
565  {
567  if ($morning_aggr > 0 && $i == $morning_aggr)
568  {
569  $hours[$i][$num_day]['txt'] = sprintf('%02d:00',0)."-".
570  sprintf('%02d:00',ceil(($i+1)/60));
571  }
572  else
573  {
574  $hours[$i][$num_day]['txt'].= sprintf('%02d:%02d',floor($i/60),$i%60);
575  }
576  if ($evening_aggr < 23*60 && $i == $evening_aggr)
577  {
578  $hours[$i][$num_day]['txt'].= "-".sprintf('%02d:00',23);
579  }
580  break;
581 
583  if ($morning_aggr > 0 && $i == $morning_aggr)
584  {
585  $hours[$i][$num_day]['txt'] = date('h a',mktime(0,0,0,1,1,2000))."-";
586  }
587  $hours[$i][$num_day]['txt'].= date('h a',mktime(floor($i/60),$i%60,0,1,1,2000));
588  if ($evening_aggr < 23 && $i == $evening_aggr)
589  {
590  $hours[$i][$num_day]['txt'].= "-".date('h a',mktime(23,0,0,1,1,2000));
591  }
592  break;
593  }
594  }
595 
596  $date_info = $date->get(IL_CAL_FKT_GETDATE,'','UTC');
597 
598 
599  foreach($daily_apps as $app)
600  {
601  // fullday appointment are not relavant
602  if($app['fullday'])
603  {
604  continue;
605  }
606  // start hour for this day
607  if($app['start_info']['mday'] != $date_info['mday'])
608  {
609  $start = 0;
610  }
611  else
612  {
613  $start = $app['start_info']['hours']*60+$app['start_info']['minutes'];
614  }
615  // end hour for this day
616  if($app['end_info']['mday'] != $date_info['mday'])
617  {
618  $end = 23*60;
619  }
620  elseif($app['start_info']['hours'] == $app['end_info']['hours'])
621  {
622  $end = $start+$raster;
623  }
624 
625  else
626  {
627  $end = $app['end_info']['hours']*60+$app['end_info']['minutes'];
628  }
629 
630  // set end to next hour for screen readers
631  if ($ilUser->prefs["screen_reader_optimization"])
632  {
633  $end = $start+$raster;
634  }
635 
636  if ($start < $morning_aggr)
637  {
638  $start = $morning_aggr;
639  }
640  if ($end <= $morning_aggr)
641  {
642  $end = $morning_aggr+$raster;
643  }
644  if ($start > $evening_aggr)
645  {
646  $start = $evening_aggr;
647  }
648  if ($end > $evening_aggr+$raster)
649  {
650  $end = $evening_aggr+$raster;
651  }
652  if ($end <= $start)
653  {
654  $end = $start+$raster;
655  }
656 
657  // map start and end to raster
658  $start = floor($start/$raster)*$raster;
659  $end = ceil($end/$raster)*$raster;
660 
661  $first = true;
662  for($i = $start;$i < $end;$i+=$raster)
663  {
664  if($first)
665  {
666  if (!$ilUser->prefs["screen_reader_optimization"])
667  {
668  $app['rowspan'] = ceil(($end - $start)/$raster);
669  }
670  else // screen readers get always a rowspan of 1
671  {
672  $app['rowspan'] = 1;
673  }
674  $hours[$i][$num_day]['apps_start'][] = $app;
675  $first = false;
676  }
677  $hours[$i][$num_day]['apps_num']++;
678  }
679  }
680  return $hours;
681  }
682 
690  protected function calculateColspans($hours)
691  {
692  global $ilUser;
693 
694  foreach($hours as $hour_num => $hours_per_day)
695  {
696  foreach($hours_per_day as $num_day => $hour)
697  {
698  $colspans[$num_day] = max($colspans[$num_day],$hour['apps_num']);
699 
700  // screen reader: always one col
701  if ($ilUser->prefs["screen_reader_optimization"])
702  {
703  $colspans[$num_day] = 1;
704  }
705  }
706  }
707  return $colspans;
708  }
709 
710 
711 }
712 
713 ?>