addLegend('') ->setAttribute('class', 'error'); foreach ($errors as $error) { $element = new ElementP(); $element->setText(get_vocab($error)); $fieldset-> addElement($element); } return $fieldset; } function get_fieldset_general(array $data) : ElementFieldset { global $timezone, $auth; $fieldset = new ElementFieldset(); $fieldset->addLegend(get_vocab('general_settings')); // Area name $field = new FieldInputText(); $field->setLabel(get_vocab('name')) ->setControlAttributes(array('id' => 'area_name', 'name' => 'area_name', 'required' => true, 'maxlength' => maxlength('area.area_name'), 'value' => $data['area_name'])); $fieldset->addElement($field); // Sort key $field = new FieldInputText(); $field->setLabel(get_vocab('sort_key')) ->setLabelAttributes(array('title' => get_vocab('sort_key_note'))) ->setControlAttributes(array('id' => 'sort_key', 'name' => 'sort_key', 'value' => $data['sort_key'], 'maxlength' => maxlength('area.sort_key'))); $fieldset->addElement($field); // Area admin email $field = new FieldInputEmail(); $field->setLabel(get_vocab('area_admin_email')) ->setLabelAttribute('title', get_vocab('email_list_note')) ->setControlAttributes(array('id' => 'area_admin_email', 'name' => 'area_admin_email', 'value' => $data['area_admin_email'], 'multiple' => true)); $fieldset->addElement($field); // The custom HTML if ($auth['allow_custom_html']) { $field = new FieldTextarea(); $field->setLabel(get_vocab('custom_html')) ->setLabelAttribute('title', get_vocab('custom_html_note')) ->setControlAttribute('name', 'custom_html') ->setControlText($data['custom_html'] ?? ''); $fieldset->addElement($field); } // Timezone $field = new FieldSelect(); $field->setLabel(get_vocab('timezone')) ->setControlAttributes(array('id' => 'area_timezone', 'name' => 'area_timezone')) ->addSelectOptions(get_timezone_options(), $timezone, true); $fieldset->addElement($field); // Default type $options = get_type_options(false); if (count($options)>0) { $field = new FieldSelect(); $field->setLabel(get_vocab('default_type')) ->setControlAttribute('name', 'area_default_type') ->addSelectOptions($options, $data['default_type'], true); $fieldset->addElement($field); } // Status - Enabled or Disabled $options = array('0' => get_vocab('enabled'), '1' => get_vocab('disabled')); $value = ($data['disabled']) ? '1' : '0'; $field = new FieldInputRadioGroup(); $field->setAttribute('id', 'status') ->setLabel(get_vocab('status')) ->setLabelAttributes(array('title' => get_vocab('disabled_area_note'))) ->addRadioOptions($options, 'area_disabled', $value, true); $fieldset->addElement($field); // Mode - Times or Periods $options = array('1' => get_vocab('mode_periods'), '0' => get_vocab('mode_times')); $value = ($data['enable_periods']) ? '1' : '0'; $field = new FieldInputRadioGroup(); $field->setAttribute('id', 'mode') ->setLabel(get_vocab('mode')) ->addRadioOptions($options, 'area_enable_periods', $value, true); $fieldset->addElement($field); // Times along the top $field = new FieldInputCheckbox(); $field->setLabel(get_vocab('times_along_top')) ->setControlAttribute('name', 'area_times_along_top') ->setControlChecked($data['times_along_top']); $fieldset->addElement($field); return $fieldset; } function get_fieldset_times() : ElementFieldset { global $enable_periods; global $morningstarts, $morningstarts_minutes; global $eveningends, $eveningends_minutes; global $resolution, $default_duration, $default_duration_all_day; $fieldset = new ElementFieldset(); $fieldset->setAttribute('id', 'time_settings'); // If we're using JavaScript, don't display the time settings section // if we're using periods (the JavaScript will display it if we change) if ($enable_periods) { $fieldset->setAttribute('class', 'js_none'); } $span = new ElementSpan(); $span->setAttribute('class', 'js_none') ->setText(' (' . get_vocab('times_only') . ')'); $legend = new ElementLegend(); $legend->setText(get_vocab('time_settings'), true) ->addElement($span); $fieldset->addLegend($legend); // First slot start $field = new FieldInputTime(); $value = sprintf('%02d:%02d', $morningstarts, $morningstarts_minutes); $field->setLabel(get_vocab('area_first_slot_start')) ->setControlAttributes(array('id' => 'area_start_first_slot', 'name' => 'area_start_first_slot', 'value' => $value, 'required' => true)); $fieldset->addElement($field); // Resolution $field = new FieldInputNumber(); $field->setLabel(get_vocab('area_res_mins')) ->setControlAttributes(array('id' => 'area_res_mins', 'name' => 'area_res_mins', 'min' => '1', 'value' => (int) $resolution/60, 'required' => true)); $fieldset->addElement($field); // Duration $field = new FieldInputNumber(); $field->setLabel(get_vocab('area_def_duration_mins')) ->setControlAttributes(array('id' => 'area_def_duration_mins', 'name' => 'area_def_duration_mins', 'min' => '1', 'value' => (int) $default_duration/60, 'required' => true)); $options = array('1' => get_vocab('all_day')); $checked = ($default_duration_all_day) ? '1' : null; $checkbox_group = new FieldInputCheckboxGroup(); $checkbox_group->addCheckboxOptions($options, 'area_def_duration_all_day', $checked, true); $field->addElement($checkbox_group); $fieldset->addElement($field); // Last slot start // The contents of this field will be overwritten by JavaScript if enabled. The JavaScript version is a drop-down // select input with options limited to those times for the last slot start that are valid. The options are // dynamically regenerated if the start of the first slot or the resolution change. The code below is // therefore an alternative for non-JavaScript browsers. $field = new FieldInputTime(); $value = sprintf('%02d:%02d', $eveningends, $eveningends_minutes); $field->setAttributes(array('id' => 'last_slot', 'class' => 'js_hidden')) ->setLabel(get_vocab('area_last_slot_start')) ->setControlAttributes(array('id' => 'area_start_last_slot', 'name' => 'area_start_last_slot', 'value' => $value, 'required' => true)); $fieldset->addElement($field); return $fieldset; } function get_fieldset_periods() : ElementFieldset { global $enable_periods, $area; $fieldset = new ElementFieldset(); $fieldset->setAttribute('id', 'period_settings'); // If we're using JavaScript, don't display the periods settings section // if we're using rimes (the JavaScript will display it if we change) if (!$enable_periods) { $fieldset->setAttribute('class', 'js_none'); } $fieldset->addLegend(get_vocab('period_settings')); $this_area_periods = Periods::getForArea($area); // For the JavaScript to work, and MRBS to make sense, there has to be at least // one period defined. So if for some reason, which shouldn't happen, there aren't // any periods defined, then force there to be one by creating a single period name // with an empty string. Because the input is a required input, then it will have // to be saved with a period name. if (empty($this_area_periods)) { $this_area_periods = [new Period('')]; $using_period_times = false; } else { $using_period_times = isset($this_area_periods->current()->start); } // TODO: Store use_period_times in the database, so that the times are not lost. // TODO: At the moment it's just used by the JavaScript to toggle the display. $field = new FieldInputCheckbox(); $field->setLabel(get_vocab('use_period_times')) ->setControlAttribute('name', 'use_period_times') ->setControlChecked($using_period_times); $fieldset->addElement($field); foreach ($this_area_periods as $period) { // The period name $field = new FieldInputText(); // The period times $period_times = new ElementDiv(); $period_times->setAttribute('class', 'period_times'); // The period start time $start = new ElementInputTime(); $start->setAttributes(['name' => 'period_starts[]', 'required' => true]); if (isset($period->start)) { $start->setAttribute('value', $period->start); } // A separator; CSS will fill its content. $separator = new ElementSpan(); $separator->setAttribute('class', 'period_separator'); // The period end time $end = new ElementInputTime(); $end->setAttributes(['name' => 'period_ends[]', 'required' => true]); if (isset($period->end)) { $end->setAttribute('value', $period->end); } $period_times->addElement($start); $period_times->addElement($separator); $period_times->addElement($end); // The delete button; CSS will fill its content. $span = new ElementSpan(); $span->setAttribute('class', 'delete_period'); $field->setAttribute('class', 'period_name') ->setControlAttributes(array('name' => 'area_periods[]', 'value' => $period->name, 'required' => true), false) ->addElement($period_times) ->addElement($span); $fieldset->addElement($field); } $field = new FieldButton(); $field->setControlAttributes(array('type' => 'button', 'id' => 'add_period')) ->setControlText(get_vocab('add_period')); $fieldset->addElement($field); return $fieldset; } function get_fieldset_create_ahead() : ElementFieldset { global $min_create_ahead_secs, $max_create_ahead_secs, $min_create_ahead_enabled, $max_create_ahead_enabled; $fieldset = new ElementFieldset(); $fieldset->addLegend(get_vocab('booking_creation')); // Minimum create ahead $param_names = array( 'enabler' => 'area_min_create_ahead_enabled', 'quantity' => 'area_min_create_ahead_value', 'units' => 'area_min_create_ahead_units', ); $field = new FieldTimeWithUnits($param_names, $min_create_ahead_enabled, $min_create_ahead_secs); $field->setLabel(get_vocab('min_book_ahead')); $fieldset->addElement($field); // Maximum create ahead // TODO: add some kind of note about exempt types $param_names = array( 'enabler' => 'area_max_create_ahead_enabled', 'quantity' => 'area_max_create_ahead_value', 'units' => 'area_max_create_ahead_units', ); $field = new FieldTimeWithUnits($param_names, $max_create_ahead_enabled, $max_create_ahead_secs); $field->setLabel(get_vocab('max_book_ahead')); $fieldset->addElement($field); return $fieldset; } function get_fieldset_delete_ahead() : ElementFieldset { global $min_delete_ahead_secs, $max_delete_ahead_secs, $min_delete_ahead_enabled, $max_delete_ahead_enabled; $fieldset = new ElementFieldset(); $fieldset->addLegend(get_vocab('booking_deletion')); // Minimum delete ahead $param_names = array( 'enabler' => 'area_min_delete_ahead_enabled', 'quantity' => 'area_min_delete_ahead_value', 'units' => 'area_min_delete_ahead_units', ); $field = new FieldTimeWithUnits($param_names, $min_delete_ahead_enabled, $min_delete_ahead_secs); $field->setLabel(get_vocab('min_book_ahead')); $fieldset->addElement($field); // Maximum delete ahead $param_names = array( 'enabler' => 'area_max_delete_ahead_enabled', 'quantity' => 'area_max_delete_ahead_value', 'units' => 'area_max_delete_ahead_units', ); $field = new FieldTimeWithUnits($param_names, $max_delete_ahead_enabled, $max_delete_ahead_secs); $field->setLabel(get_vocab('max_book_ahead')); $fieldset->addElement($field); return $fieldset; } function get_fieldset_max_number() : ElementFieldset { global $interval_types, $max_per_interval_area_enabled, $max_per_interval_global_enabled, $max_per_interval_area, $max_per_interval_global; $fieldset = new ElementFieldset(); $fieldset->setAttribute('class', 'max_limits') ->addLegend(get_vocab('booking_limits')); // Add the column headings $field = new FieldDiv; $span_area = new ElementSpan(); $span_area->setText(get_vocab('this_area')); $span_global = new ElementSpan(); $span_global->setAttribute('title', get_vocab('whole_system_note')) ->setText(get_vocab('whole_system')); $field->addControlElement($span_area) ->addControlElement($span_global); $fieldset->addElement($field); // Then do the individual settings foreach ($interval_types as $interval_type) { $field = new FieldDiv; $checkbox_area = new ElementInputCheckbox(); $checkbox_area->setAttributes(array('name' => "area_max_per_{$interval_type}_enabled", 'id' => "area_max_per_{$interval_type}_enabled", 'class' => 'enabler')) ->setChecked($max_per_interval_area_enabled[$interval_type]); $number_area = new ElementInputNumber(); $number_area->setAttributes(array('min' => '0', 'name' => "area_max_per_$interval_type", 'value' => $max_per_interval_area[$interval_type])); // Wrap the area and global controls in