/[drupal]/contributions/modules/duration/duration_element.module
ViewVC logotype

Contents of /contributions/modules/duration/duration_element.module

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


Revision 1.5 - (show annotations) (download) (as text)
Tue May 27 01:47:46 2008 UTC (18 months ago) by jpetso
Branch: MAIN
CVS Tags: DRUPAL-6--1-0-RC1, DRUPAL-6--1-0-RC2, DRUPAL-6--1-0, HEAD
Changes since 1.4: +6 -6 lines
File MIME type: text/x-php
* Have a lower-case API even for the object, like Views 2.
  Looks much more natural this way, too.
* Separate conversion factors from general metrics properties
  and make it possible for an object user to change them.
1 <?php
2 // $Id: duration_element.module,v 1.4 2008/04/30 10:53:01 jpetso Exp $
3
4 /**
5 * @file
6 * A form element for entering time durations.
7 *
8 * Copyright 2007, 2008 by Jakob Petsovits <jpetso@gmx.at>
9 * Distributed under the GNU General Public Licence version 2 or higher,
10 * as published by the FSF on http://www.gnu.org/copyleft/gpl.html
11 */
12
13 /**
14 * Implementation of hook_elements():
15 * Register the duration widget with the Forms API and set default values.
16 */
17 function duration_element_elements() {
18 return array(
19 'duration_combo' => array(
20 '#input' => TRUE,
21 '#largest_metric' => 'years',
22 '#smallest_metric' => 'seconds',
23 '#display_inline' => TRUE,
24 '#size' => 3, // size of each input textbox
25 '#maxlength' => 4, // maxlength of each input textbox
26 '#process' => array('duration_element_combo_process'),
27 ),
28 'duration_select' => array(
29 '#input' => TRUE,
30 '#options' => array(),
31 '#format_callback' => 'duration_format_list',
32 '#format_callback_arguments' => array(),
33 '#process' => array('duration_element_select_process'),
34 ),
35 );
36 }
37
38
39 /**
40 * Value callback, so that the #default_value is not directly assigned
41 * but transformed into an array for the nested "$metric" elements.
42 * form.inc produces a nasty error if we don't do that.
43 */
44 function form_type_duration_combo_value($element, $edit = FALSE) {
45 if (func_num_args() == 1) {
46 if (is_object($element['#default_value'])) {
47 $duration = $element['#default_value'];
48 // Cut off metrics that are not provided as input fields.
49 $duration->set_granularity(
50 $element['#smallest_metric'], $element['#largest_metric']
51 );
52 }
53 else { // no default value, use a brand new duration object instead
54 $duration = duration_create();
55 }
56
57 $values = array(
58 'type' => $duration->type(),
59 );
60 foreach ($duration->to_array() as $metric => $value) {
61 $values[$metric] = $value;
62 }
63 }
64 else {
65 $values = $edit;
66 $values['type'] = isset($values['months']) ? 'months' : 'weeks';
67 }
68 return $values;
69 }
70
71 /**
72 * The 'process' callback for 'duration_combo' form elements.
73 * Called after defining the form and while building it.
74 */
75 function duration_element_combo_process($element) {
76 if (isset($element['#element_validate'])) {
77 // Before the element user gets to do his validation, make sure we do ours.
78 array_unshift($element['#element_validate'], 'duration_element_combo_validate');
79 }
80 else {
81 $element['#element_validate'] = array('duration_element_combo_validate');
82 }
83 $type = $element['#value']['type']; // 'weeks' or 'months'
84
85 // Use the format that the duration object itself is using
86 // (e.g. 'P1D' for 'months', 'P0W1D' for 'weeks') - even if that overrides
87 // the element creator's setting. We might lose data otherwise, and anyways
88 // the element creator should make sure to pass an appropriately typed object.
89 if ($type == 'weeks' && $element['#smallest_metric'] == 'months') {
90 $element['#smallest_metric'] = 'years'; // are larger than months, weeks are not
91 }
92 if ($type == 'months' && $element['#smallest_metric'] == 'weeks') {
93 $element['#smallest_metric'] = 'months';
94 }
95 if ($type == 'weeks' && $element['#largest_metric'] == 'months') {
96 $element['#largest_metric'] = 'weeks';
97 }
98 if ($type == 'months' && $element['#largest_metric'] == 'weeks') {
99 $element['#largest_metric'] = 'days'; // are smaller than weeks, months are not
100 }
101
102 $metrics = duration_metrics();
103 $used_metrics = array();
104 $encountered_largest_metric = FALSE;
105
106 foreach ($metrics as $metric) {
107 if ($metric == $element['#largest_metric']) {
108 $encountered_largest_metric = TRUE;
109 }
110 if ($encountered_largest_metric) {
111 if (($metric == 'months' && $type == 'weeks')
112 || ($metric == 'weeks' && $type == 'months')) {
113 // doesn't belong in here, don't include this metric
114 }
115 else {
116 $used_metrics[$metric] = duration_metric_t($metric);
117 }
118 }
119 if ($metric == $element['#smallest_metric']) {
120 break;
121 }
122 }
123
124 $element['#tree'] = TRUE; // so that we can nest child input elements
125 $element['#used_metrics'] = $used_metrics; // save for the validation callback
126
127 foreach ($used_metrics as $metric => $metric_t) {
128 if ($metric != $element['#smallest_metric']) {
129 // Some additional space between the text and the next textfield.
130 $metric_t = '<span style="margin-right: 0.8em;">' . $metric_t . '</span>';
131 }
132 $element[$metric] = array(
133 '#type' => 'textfield',
134 '#default_value' => $element['#value'][$metric],
135 '#size' => $element['#size'],
136 '#maxlength' => $element['#maxlength'],
137 '#prefix' => '<div class="container-inline">',
138 '#suffix' => $metric_t . '</div>',
139 );
140 }
141
142 // Don't have a maxlength in the parent element, as Form API tries to
143 // perform string operations if we've got that property.
144 unset($element['#maxlength']);
145
146 return $element;
147 }
148
149 /**
150 * The 'validate' callback for 'duration_combo' form elements.
151 * Called after values are assigned, before form validate and submit are called.
152 */
153 function duration_element_combo_validate(&$element, &$form_state) {
154 $duration = duration_create();
155
156 foreach ($element['#used_metrics'] as $metric => $metric_t) {
157 $value = $element[$metric]['#value'];
158
159 if ($value === '') {
160 $value = 0;
161 }
162 if (!is_numeric($value) || $value < 0) {
163 form_error($element[$metric],
164 t('The "@metric" value in %widget must be greater or equal 0.',
165 array('@metric' => $metric_t, '%widget' => $element['#title']))
166 );
167 $error_set = TRUE;
168 }
169 else {
170 $duration->set_value($metric, $value);
171 }
172 }
173 if ($element['#required'] && $duration->to_single_metric('seconds') == 0) {
174 form_error($element,
175 t('A non-zero duration is required for %widget.',
176 array('%widget' => $element['#title']))
177 );
178 }
179 form_set_value($element, $duration, $form_state);
180
181 // Altering the element itself is slightly non-standard (..."a hack"),
182 // but allows access to the modified value in subsequent element validators.
183 $element['#value'] = $duration;
184 }
185
186
187 /**
188 * Value callback, so that the #default_value is not directly assigned
189 * but transformed into an array for the nested 'select' element.
190 * form.inc produces a nasty error if we don't do that.
191 */
192 function form_type_duration_select_value($element, $edit = FALSE) {
193 if (func_num_args() == 1) {
194 return array('select' => $element['#default_value']);
195 }
196 }
197
198 /**
199 * The 'process' callback for the 'duration_select' element.
200 * Called after defining the form and while building it.
201 */
202 function duration_element_select_process($element) {
203 if (isset($element['#element_validate'])) {
204 // Before the element user gets to do his validation, make sure we do ours.
205 array_unshift($element['#element_validate'], 'duration_element_select_validate');
206 }
207 else {
208 $element['#element_validate'] = array('duration_element_select_validate');
209 }
210 $options = array();
211
212 foreach ($element['#options'] as $key => $duration) {
213 if (!is_object($duration)) {
214 continue;
215 }
216 $function = $element['#format_callback'];
217 $args = $element['#format_callback_arguments'];
218 array_unshift($args, $duration); // $duration as first argument
219 $options[$key] = call_user_func_array($function, $args);
220 }
221 $element['#tree'] = TRUE; // so that we can nest child input elements
222
223 $element['select'] = array(
224 '#type' => 'select',
225 '#default_value' => isset($element['#default_value'])
226 ? $element['#default_value']
227 : reset(array_keys($options)),
228 '#options' => $options,
229 '#required' => $element['#required'],
230 );
231 return $element;
232 }
233
234 /**
235 * The 'validate' callback for the 'duration_select' element.
236 * Called after values are assigned, before form validate and submit are called.
237 */
238 function duration_element_select_validate(&$element, &$form_state) {
239 // Altering the element itself is slightly non-standard (..."a hack"),
240 // but allows access to the modified value in subsequent element validators.
241 $element['#value'] = $element['select']['#value'];
242 form_set_value($element, $element['#value'], $form_state);
243 }
244
245
246 /**
247 * Implementation of hook_theme().
248 */
249 function duration_element_theme() {
250 return array(
251 'duration_combo' => array('arguments' => array('element' => NULL)),
252 'duration_select' => array('arguments' => array('element' => NULL)),
253 );
254 }
255
256 /**
257 * Theme the duration element.
258 */
259 function theme_duration_combo($element) {
260 // class="container-inline" makes child widgets align horizontally.
261 $children = ($element['#display_inline'])
262 ? '<div class="container-inline">' . $element['#children'] . '</div>'
263 : $element['#children'];
264
265 return theme('form_element', $element, $children);
266 }
267
268 function theme_duration_select($element) {
269 // class="container-inline" not only makes child widgets align horizontally,
270 // it also reduces the unnecessarily large space between title and element.
271 return theme('form_element', $element,
272 '<div class="container-inline">' . $element['#children'] . '</div>'
273 );
274 }

  ViewVC Help
Powered by ViewVC 1.1.2