Index: trunk/extensions/SemanticForms/includes/SF_FormPrinter.inc |
— | — | @@ -1,6 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Handles the display and running of a user-created form. |
| 4 | + * Handles the creation and running of a user-created form. |
5 | 5 | * |
6 | 6 | * @author Yaron Koren |
7 | 7 | * @author Nils Oppermann |
— | — | @@ -33,6 +33,8 @@ |
34 | 34 | $form_text = wfMsg( 'protectedpagetext' ); |
35 | 35 | } |
36 | 36 | } |
| 37 | + $javascript_text = ""; |
| 38 | + $js_validation_calls = array(); |
37 | 39 | |
38 | 40 | // Remove <noinclude> sections and <includeonly> tags from form definition |
39 | 41 | $form_def = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $form_def); |
— | — | @@ -44,6 +46,7 @@ |
45 | 47 | $start_position = 0; |
46 | 48 | $section_start = 0; |
47 | 49 | $free_text_was_included = false; |
| 50 | + $all_values_for_template = array(); |
48 | 51 | while ($brackets_loc = strpos($form_def, "{{{", $start_position)) { |
49 | 52 | $brackets_end_loc = strpos($form_def, "}}}", $brackets_loc); |
50 | 53 | $bracketed_string = substr($form_def, $brackets_loc + 3, $brackets_end_loc - ($brackets_loc + 3)); |
— | — | @@ -56,25 +59,23 @@ |
57 | 60 | $section_start = $brackets_loc; |
58 | 61 | } |
59 | 62 | $start_position = $brackets_loc + 1; |
60 | | - } |
| 63 | + } // end while |
61 | 64 | $form_def_sections[] = trim(substr($form_def, $section_start)); |
62 | 65 | |
63 | 66 | // cycle through form definition file (and possibly an existing article |
64 | 67 | // as well), finding template and field declarations and replacing them |
65 | 68 | // with form elements, either blank or pre-populated, as appropriate |
66 | 69 | $all_fields = array(); |
67 | | - $passed_validation = true; |
68 | 70 | $data_text = ""; |
69 | 71 | $template_name = ""; |
70 | | - $full_template_name = ""; |
71 | | - $instance_was_deleted = false; |
72 | 72 | $allow_multiple = false; |
| 73 | + $instance_num = 0; |
| 74 | + $all_instances_printed = false; |
73 | 75 | $strict_parsing = false; |
74 | 76 | for ($section_num = 0; $section_num < count($form_def_sections); $section_num++) { |
75 | 77 | $tif = new SFTemplateInForm(); |
76 | 78 | $start_position = 0; |
77 | 79 | $template_text = ""; |
78 | | - $instance_added = false; |
79 | 80 | // the append is there to ensure that the original array doesn't get |
80 | 81 | // modified; is it necessary? |
81 | 82 | $section = " " . $form_def_sections[$section_num]; |
— | — | @@ -101,23 +102,8 @@ |
102 | 103 | } |
103 | 104 | } |
104 | 105 | } |
105 | | - // increment instance_num (used for query string) if it's |
106 | | - // a repeated template, or if user has hit 'add' button |
107 | | - // - this logic might not need to be this complicated |
108 | | - if ($allow_multiple) { |
109 | | - if ($old_template_name == $template_name || $repeat_section) { |
110 | | - $instance_num++; |
111 | | - } else { |
112 | | - $instance_num = 1; |
113 | | - } |
114 | | - $repeat_section = false; |
115 | | - $full_template_name = $query_template_name . '_' . $instance_num; |
116 | | - } else { |
117 | | - $instance_num = 1; |
118 | | - $full_template_name = $query_template_name; |
119 | | - } |
120 | 106 | // if this is the first instance, add the label in the form |
121 | | - if ($instance_num == 1 && isset($template_label)) { |
| 107 | + if (($old_template_name != $template_name) && isset($template_label)) { |
122 | 108 | $form_text .= "<fieldset>\n"; |
123 | 109 | $form_text .= "<legend>$template_label</legend>\n"; |
124 | 110 | } |
— | — | @@ -125,15 +111,7 @@ |
126 | 112 | $all_fields = $tif->getAllFields(); |
127 | 113 | // remove template tag |
128 | 114 | $section = substr_replace($section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); |
129 | | - // if this is an 'allowed multiple' template, and user requested a |
130 | | - // delete of this instance, increment the instance_num; that will |
131 | | - // skip over all the fields of this template in the query |
132 | | - $delete_cur_instance = false; |
133 | | - $full_template_values = $wgRequest->getArray($full_template_name); |
134 | | - if ($allow_multiple && $full_template_values['delete'] != null) { |
135 | | - $delete_cur_instance = true; |
136 | | - $instance_was_deleted = true; |
137 | | - } |
| 115 | + $template_instance_query_values = $wgRequest->getArray($query_template_name); |
138 | 116 | // if we are editing a page, and this template can be found more than |
139 | 117 | // once in that page, and multiple values are allowed, repeat this |
140 | 118 | // section |
— | — | @@ -148,11 +126,9 @@ |
149 | 127 | // instances of templates, one that doesn't involve re-parsing |
150 | 128 | // the same tags, but I don't know what it is. |
151 | 129 | if (preg_match_all('/\{\{' . $tif->template_name . '(.*?)\}\}/mis', $existing_page_content, $matches)) { |
152 | | - if (count($matches[0]) > 1) { |
153 | | - $repeat_section = true; |
154 | | - } |
| 130 | + $instance_num++; |
155 | 131 | } else { |
156 | | - $delete_cur_instance = true; |
| 132 | + $all_instances_printed = true; |
157 | 133 | } |
158 | 134 | } |
159 | 135 | // get the first instance of this template on the page being edited, |
— | — | @@ -183,34 +159,41 @@ |
184 | 160 | $existing_page_content = str_replace($matches[0], '', $existing_page_content); |
185 | 161 | } |
186 | 162 | } |
187 | | - // now the same check as above, but if the input came from a form - |
188 | | - // if multiple instances of this template are allowed, and the template |
189 | | - // name of the current instance is the same as the next one, re-use |
190 | | - // the template section on the next loop through |
191 | | - if ((! $source_is_page) && $allow_multiple) { |
192 | | - $possible_next_template_name = $query_template_name . '_' . ($instance_num + 1); |
193 | | - $template_values = $wgRequest->getArray($query_template_name); |
194 | | - if (count($wgRequest->getArray($possible_next_template_name)) > 0) { |
195 | | - $repeat_section = true; |
196 | | - } elseif ($template_values['add'] != null && !$instance_added) { |
197 | | - $instance_added = true; |
198 | | - if (count($wgRequest->getArray($full_template_name)) > 0) { |
199 | | - $repeat_section = true; |
| 163 | + // if the input is from the form (meaning the user has hit one |
| 164 | + // of the bottom row of buttons), and we're dealing with a |
| 165 | + // multiple template, get the values for this instance of this |
| 166 | + // template, then delete them from the array, so we can get the |
| 167 | + // next group next time - the next() command for arrays doesn't |
| 168 | + // seem to work here |
| 169 | + if ((! $source_is_page) && $allow_multiple && $wgRequest) { |
| 170 | + $all_instances_printed = true; |
| 171 | + if ($old_template_name != $template_name) { |
| 172 | + $all_values_for_template = $wgRequest->getArray($query_template_name); |
| 173 | + } |
| 174 | + if ($all_values_for_template) { |
| 175 | + $cur_key = key($all_values_for_template); |
| 176 | + // skip the input coming in from the "starter" div |
| 177 | + if ($cur_key == 'num') { |
| 178 | + unset($all_values_for_template[$cur_key]); |
| 179 | + $cur_key = key($all_values_for_template); |
200 | 180 | } |
201 | | - } elseif (count($wgRequest->getArray($full_template_name)) == 0 && !$instance_added) { |
202 | | - $delete_cur_instance = true; |
| 181 | + if ($template_instance_query_values = current($all_values_for_template)) { |
| 182 | + $all_instances_printed = false; |
| 183 | + unset($all_values_for_template[$cur_key]); |
| 184 | + } |
203 | 185 | } |
204 | 186 | } |
205 | 187 | } elseif ($tag_title == 'end template') { |
206 | 188 | // remove this tag, reset some variables, and close off form HTML tag |
207 | 189 | $section = substr_replace($section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); |
208 | | - $allow_multiple = false; |
209 | 190 | $template_name = null; |
210 | | - $full_template_name = null; |
211 | 191 | if (isset($template_label)) { |
212 | 192 | $form_text .= "</fieldset>\n"; |
213 | 193 | unset ($template_label); |
214 | 194 | } |
| 195 | + $allow_multiple = false; |
| 196 | + $all_instances_printed = false; |
| 197 | + $instance_num = 0; |
215 | 198 | } elseif ($tag_title == 'field') { |
216 | 199 | $field_name = trim($tag_components[1]); |
217 | 200 | // cycle through the other components |
— | — | @@ -256,10 +239,8 @@ |
257 | 240 | } |
258 | 241 | } |
259 | 242 | } |
260 | | - $error_str = null; |
261 | 243 | // get the value from the request, if it's there |
262 | | - $full_template_values = $wgRequest->getArray($full_template_name); |
263 | | - $cur_value = $full_template_values[$field_name]; |
| 244 | + $cur_value = $template_instance_query_values[$field_name]; |
264 | 245 | if ($cur_value && ! is_array($cur_value)) { |
265 | 246 | $cur_value = Sanitizer::safeEncodeAttribute($cur_value); |
266 | 247 | } |
— | — | @@ -277,51 +258,28 @@ |
278 | 259 | $cur_value = Sanitizer::safeEncodeAttribute($cur_value); |
279 | 260 | } |
280 | 261 | } |
281 | | - // check that all mandatory values have been filled in |
282 | | - if ($form_submitted && $is_mandatory && $cur_value == "") { |
283 | | - $error_str = wfMsg('sf_blank_error'); |
284 | | - $passed_validation = false; |
285 | | - } |
286 | | - // the template display name might be different from what's in |
287 | | - // the query string, if a previous instance was deleted |
288 | | - if ($allow_multiple && $instance_was_deleted) { |
289 | | - $template_display_name = $query_template_name . '_' . ($instance_num - 1); |
290 | | - } else { |
291 | | - $template_display_name = $full_template_name; |
292 | | - } |
| 262 | + $template_display_name = $query_template_name; |
293 | 263 | // handle non-template fields - 'page title' and 'free text' |
294 | 264 | if ($template_name == '') { |
295 | 265 | if ($field_name == 'page title') { |
296 | | - // if we're adding a new page, make it an input field, and |
297 | | - // possibly validate it; otherwise just put in the name |
298 | | - if ($page_title == null) { |
299 | | - $title = $wgRequest->getVal('page_title'); |
300 | | - if ($form_submitted && $title == "") { |
301 | | - $error_str = wfMsg('sf_blank_error'); |
302 | | - $passed_validation = false; |
303 | | - } |
304 | | - if ($size == null) $size = 35; |
305 | | - $new_text = SFFormPrinter::textEntryHTML($size, '', $field_name, $title, $error_str); |
306 | | - } else { |
307 | | - $new_text = $page_title; |
308 | | - } |
309 | | - $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); |
| 266 | + // the actual value should be non-null - stick it in |
| 267 | + $new_text = $page_title; |
310 | 268 | } elseif ($field_name == 'free text') { |
311 | 269 | // add placeholders for the free text in both the form and |
312 | 270 | // the page, using <free_text> tags - once all the free text |
313 | 271 | // is known (at the end), it will get substituted in |
314 | 272 | if ($is_hidden) { |
315 | | - $new_text = SFFormPrinter::hiddenFieldHTML(null, 'free_text', '<free_text>'); |
| 273 | + $new_text = SFFormPrinter::hiddenFieldHTML('free_text', '<free_text>'); |
316 | 274 | } else { |
317 | 275 | if ($num_rows == null) $num_rows = 5; |
318 | 276 | if ($num_cols == null) $num_cols = 30; |
319 | | - $new_text = SFFormPrinter::textAreaHTML($num_rows, $num_cols, null, 'free_text', '<free_text>', null); |
| 277 | + $new_text = SFFormPrinter::textAreaHTML($num_rows, $num_cols, 'free_text', '<free_text>', null); |
320 | 278 | } |
321 | | - $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); |
322 | 279 | $free_text_was_included = true; |
323 | 280 | // add a similar placeholder to the data text |
324 | 281 | $data_text .= "<free_text>\n\n"; |
325 | 282 | } |
| 283 | + $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); |
326 | 284 | } else { // this field is part of a template |
327 | 285 | if (is_array($cur_value)) { |
328 | 286 | // if it has 1 or 2 elements, assume it's a checkbox; if it has |
— | — | @@ -361,9 +319,17 @@ |
362 | 320 | } else { // value is not an array |
363 | 321 | $cur_value_in_template = $cur_value; |
364 | 322 | } |
365 | | - $new_text = SFFormPrinter::formTemplateFieldHTML($template_display_name, $field_name, $instance_num, |
| 323 | + if ($query_template_name == null || $query_template_name == '') |
| 324 | + $input_name = $field_name; |
| 325 | + elseif ($allow_multiple) |
| 326 | + // 'num' will get replaced by an actual index, either in PHP |
| 327 | + // or in Javascript, later on |
| 328 | + $input_name = $query_template_name . '[num][' . $field_name . ']'; |
| 329 | + else |
| 330 | + $input_name = $query_template_name . '[' . $field_name . ']'; |
| 331 | + $new_text = SFFormPrinter::formTemplateFieldHTML($field_name, $input_name, $allow_multiple, |
366 | 332 | $cur_value, $is_mandatory, $is_hidden, $input_type, $size, $num_rows, $num_cols, $no_autocomplete, |
367 | | - $autocomplete_category, $error_str, $all_fields, $strict_parsing); |
| 333 | + $autocomplete_category, $all_fields, $strict_parsing); |
368 | 334 | if ($new_text) { |
369 | 335 | if (is_numeric($field_name)) { |
370 | 336 | // if the value is null, don't include it at all - |
— | — | @@ -376,6 +342,12 @@ |
377 | 343 | $template_text .= "\n|$field_name=$cur_value_in_template"; |
378 | 344 | } |
379 | 345 | $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); |
| 346 | + // also add to Javascript validation code |
| 347 | + if ($is_mandatory) { |
| 348 | + $input_id = "input_" . $gTabIndex; |
| 349 | + $info_id = "info_" . $gTabIndex; |
| 350 | + $js_validation_calls[] = "validate_mandatory_field ('$input_id', '$info_id')"; |
| 351 | + } |
380 | 352 | } else { |
381 | 353 | $start_position = $brackets_end_loc; |
382 | 354 | } |
— | — | @@ -386,43 +358,49 @@ |
387 | 359 | } |
388 | 360 | } // end while |
389 | 361 | |
390 | | - if ($full_template_name != '' && ! $delete_cur_instance) { |
| 362 | + if (! $all_instances_printed && ($template_text != '')) { |
391 | 363 | // add another newline before the final bracket, if this template |
392 | 364 | // call is already more than one line |
393 | 365 | if (strpos($template_text, "\n")) { |
394 | 366 | $template_text .= "\n"; |
395 | 367 | } |
396 | | - $template_text .= "}}\n"; |
397 | | - // if this is the last of its kind, add another newline |
398 | | - if ($allow_multiple == false || $repeat_section == false) |
399 | | - $template_text .= "\n"; |
| 368 | + $template_text .= "}}\n\n"; |
| 369 | + // TODO - should instances of the same template not be separated |
| 370 | + // by a blank line? if so, the following code could be used: |
| 371 | + //if (($data_text != "") && |
| 372 | + // (! $allow_multiple || $old_template_name != $template_name)) { |
| 373 | + // $data_text .= "\n"; |
| 374 | + //} |
400 | 375 | $data_text .= $template_text; |
401 | 376 | } |
402 | 377 | if ($allow_multiple) { |
403 | | - if (! $delete_cur_instance) { |
404 | | - $input_name = $full_template_name . '[delete]'; |
| 378 | + if (! $all_instances_printed) { |
| 379 | + $section = str_replace('[num]', "[{$instance_num}a]", $section); |
405 | 380 | $remove_text = wfMsg('sf_editdata_remove'); |
406 | | - $gTabIndex++; |
407 | 381 | $form_text .=<<<END |
408 | | - <div style="background-color:#cccccc; padding:7px; margin:10px 0px 10px 0px;"> |
| 382 | + <div id="wrapper_$gTabIndex" class="multiple_template"> |
409 | 383 | $section |
410 | | - <input tabindex="$gTabIndex" type="submit" name="$input_name" value="$remove_text" $gDisabledText> |
| 384 | + <input type="button" onclick="blankInstance('wrapper_$gTabIndex');" value="$remove_text" tabindex="$gTabIndex" /> |
411 | 385 | </div> |
412 | 386 | |
413 | 387 | END; |
414 | | - } |
415 | | - if ($repeat_section) { |
416 | 388 | // this will cause the section to be re-parsed on the next go |
417 | 389 | $section_num--; |
418 | 390 | } else { |
419 | 391 | // this is the last instance of this template - stick an 'add' |
420 | 392 | // button in the form |
421 | | - $input_name = $template_name . '[add]'; |
| 393 | + $form_text .=<<<END |
| 394 | + <div id="starter_$query_template_name" class="multiple_template" style="display: none;"> |
| 395 | + $section |
| 396 | + </div> |
| 397 | + <div id="main_$query_template_name"></div> |
| 398 | + |
| 399 | +END; |
422 | 400 | $add_another = wfMsg('sf_editdata_addanother'); |
423 | | - $gTabIndex++; |
424 | 401 | $form_text .=<<<END |
425 | 402 | <p style="margin-left:10px;"> |
426 | | - <input tabindex="$gTabIndex" type="submit" name="$input_name" value="$add_another" $gDisabledText></p> |
| 403 | + <input type="hidden" value="0" id="numElements" /> |
| 404 | + <p><input type="button" onclick="addInstance('starter_$query_template_name', 'main_$query_template_name', '$gTabIndex');" value="$add_another" tabindex="$gTabIndex" /></p> |
427 | 405 | |
428 | 406 | END; |
429 | 407 | } |
— | — | @@ -436,7 +414,7 @@ |
437 | 415 | // 'free text' input at the bottom of the form |
438 | 416 | if (! $free_text_was_included) { |
439 | 417 | $form_text .= ' <fieldset><legend>' . wfMsg('sf_editdata_freetextlabel') . "</legend>\n"; |
440 | | - $form_text .= SFFormPrinter::textAreaHTML(5, 30, null, 'free_text', '<free_text>', null); |
| 418 | + $form_text .= SFFormPrinter::textAreaHTML(5, 30, 'free_text', '<free_text>', null); |
441 | 419 | $form_text .= " </fieldset>\n"; |
442 | 420 | } |
443 | 421 | // get free text, and add to page data, as well as retroactively |
— | — | @@ -460,77 +438,174 @@ |
461 | 439 | // now that we have it, substitute free text into the form and page |
462 | 440 | $form_text = str_replace('<free_text>', $free_text, $form_text); |
463 | 441 | $data_text = str_replace('<free_text>', $free_text, $data_text); |
464 | | - return array($form_text, $title, $data_text, $passed_validation); |
| 442 | + |
| 443 | + // add general Javascript code |
| 444 | + $blank_error_str = wfMsg('sf_blank_error'); |
| 445 | + $javascript_text .=<<<END |
| 446 | + |
| 447 | +function validate_mandatory_field(field_id, info_id) { |
| 448 | + field = document.getElementById(field_id); |
| 449 | + if (field.value.replace(/\s+/, '') == '') { |
| 450 | + infobox = document.getElementById(info_id); |
| 451 | + infobox.innerHTML = "$blank_error_str"; |
| 452 | + //field.style.border = "1px solid red"; |
| 453 | + return false; |
| 454 | + } else { |
| 455 | + return true; |
| 456 | + } |
| 457 | +} |
| 458 | + |
| 459 | +function validate_all() { |
| 460 | + var num_errors = 0; |
| 461 | + |
| 462 | +END; |
| 463 | + foreach ($js_validation_calls as $function_call) { |
| 464 | + $javascript_text .= " if (!$function_call) num_errors += 1;\n"; |
| 465 | + } |
| 466 | + $remove_text = wfMsg('sf_editdata_remove'); |
| 467 | + $javascript_text .=<<<END |
| 468 | + return (num_errors == 0); |
| 469 | +} |
| 470 | + |
| 471 | +// This Javascript code is heavily indebted to Dustin Diaz's 'add and remove |
| 472 | +// HTML elements' tutorial - http://www.dustindiaz.com/add-and-remove-html-elements-dynamically-with-javascript/ |
| 473 | +function addInstance(starter_div_id, main_div_id, tab_index) { |
| 474 | + var starter_div = document.getElementById(starter_div_id); |
| 475 | + var main_div = document.getElementById(main_div_id); |
| 476 | + var numi = document.getElementById('numElements'); |
| 477 | + var num = (document.getElementById('numElements').value -1)+ 2; |
| 478 | + numi.value = num; |
| 479 | + var newdiv = document.createElement('div'); |
| 480 | + var div_id = 'div_' + num; |
| 481 | + newdiv.setAttribute('id', div_id); |
| 482 | + newdiv.setAttribute('class', 'multiple_template'); |
| 483 | + // workaround for IE 6 bug |
| 484 | + newdiv.setAttribute('className', 'multiple_template'); |
| 485 | + // make internal ID unique for the relevant divs and spans, and replace |
| 486 | + // the [num] index with an actual unique index |
| 487 | + var orig_html = starter_div.innerHTML; |
| 488 | + orig_html = orig_html.replace(/input_/g, 'input_' + num + '_'); |
| 489 | + orig_html = orig_html.replace(/info_/g, 'info_' + num + '_'); |
| 490 | + orig_html = orig_html.replace(/div_/g, 'div_' + num + '_'); |
| 491 | + orig_html = orig_html.replace(/\[num\]/g, '[' + num + ']'); |
| 492 | + newdiv.innerHTML = orig_html + '<input type="button" onclick="removeInstance(\'' + main_div_id + '\', \'' + div_id + '\');" value="$remove_text" tabindex="' + tab_index + '" />'; |
| 493 | + main_div.appendChild(newdiv); |
| 494 | +} |
| 495 | + |
| 496 | +function removeInstance(main_div_id, this_div_id) { |
| 497 | + var d = document.getElementById(main_div_id); |
| 498 | + var olddiv = document.getElementById(this_div_id); |
| 499 | + d.removeChild(olddiv); |
| 500 | +} |
| 501 | + |
| 502 | +// hack function - an element that's not a child of anything can't be |
| 503 | +// removed, so do the next best thing: set its contents to blank and its |
| 504 | +// display to 'none' |
| 505 | +function blankInstance(div_id) { |
| 506 | + var d = document.getElementById(div_id); |
| 507 | + d.innerHTML = ""; |
| 508 | + d.style.display = "none"; |
| 509 | +} |
| 510 | + |
| 511 | +END; |
| 512 | + return array($form_text, $javascript_text, $title, $data_text); |
465 | 513 | } |
466 | 514 | |
467 | | - function formTemplateFieldHTML($template_name, $field_name, $instance_num, $cur_value, $is_mandatory, $is_hidden, $input_type, $size, $num_rows, $num_cols, $no_autocomplete, $autocomplete_category, $error_str, $all_fields, $strict_parsing) { |
| 515 | + function formTemplateFieldHTML($field_name, $input_name, $part_of_multiple, $cur_value, $is_mandatory, $is_hidden, $input_type, $size, $num_rows, $num_cols, $no_autocomplete, $autocomplete_category, $all_fields, $strict_parsing) { |
| 516 | + global $gTabIndex; |
468 | 517 | |
469 | 518 | // see if this field matches one of the fields defined for this template - |
470 | 519 | // if it is, use all available information about that field; if it's not, |
471 | 520 | // either include it in the form or not, depending on whether template |
472 | 521 | // has 'strict' setting in the form definition |
| 522 | + $the_field = null; |
473 | 523 | foreach ($all_fields as $cur_field) { |
474 | 524 | if ($field_name == $cur_field->field_name) { |
475 | | - $text = SFFormPrinter::formFieldHTML($template_name, $field_name, $cur_field, $instance_num, $cur_value, $is_mandatory, $is_hidden, $input_type, $size, $num_rows, $num_cols, $no_autocomplete, $autocomplete_category, $error_str); |
476 | | - return $text; |
| 525 | + $the_field = $cur_field; |
| 526 | + break; |
477 | 527 | } |
478 | 528 | } |
479 | | - // if we're still here, field wasn't found |
480 | | - if (! $strict_parsing) { |
481 | | - $dummy_field = new SFTemplateField(); |
482 | | - $text = SFFormPrinter::formFieldHTML($template_name, $field_name, $dummy_field, $instance_num, $cur_value, $is_mandatory, $is_hidden, $input_type, $size, $num_rows, $num_cols, $no_autocomplete, $autocomplete_category, $error_str); |
483 | | - return $text; |
| 529 | + if ($the_field == null) { |
| 530 | + if ($strict_parsing) |
| 531 | + return null; |
| 532 | + $the_field = new SFTemplateField(); |
484 | 533 | } |
485 | | - return null; |
| 534 | + |
| 535 | + // if this is not part of a 'multiple' template, incrememt the |
| 536 | + // global tab index (used for correct tabbing, and for creating |
| 537 | + // unique div IDs.) |
| 538 | + if (! $part_of_multiple) |
| 539 | + $gTabIndex++; |
| 540 | + |
| 541 | + // populate field object with settings from the form definition file |
| 542 | + $the_field->is_mandatory = $is_mandatory; |
| 543 | + $the_field->is_hidden = $is_hidden; |
| 544 | + $the_field->input_type = $input_type; |
| 545 | + $the_field->size = $size; |
| 546 | + $the_field->num_rows = $num_rows; |
| 547 | + $the_field->num_cols = $num_cols; |
| 548 | + $the_field->no_autocomplete = $no_autocomplete; |
| 549 | + $the_field->autocomplete_category = $autocomplete_category; |
| 550 | + $the_field->input_name = $input_name; |
| 551 | + $the_field->part_of_multiple = $part_of_multiple; |
| 552 | + $text = SFFormPrinter::formFieldHTML($the_field, $cur_value); |
| 553 | + return $text; |
486 | 554 | } |
487 | 555 | |
488 | | - function formFieldHTML($template_name, $field_name, $template_field, $instance_num, $cur_value, $is_mandatory, $is_hidden, $input_type, $size, $num_rows, $num_cols, $no_autocomplete, $autocomplete_category, $error_str) { |
| 556 | + function formFieldHTML($template_field, $cur_value) { |
489 | 557 | global $smwgContLang; |
490 | | - if ($is_hidden) { |
491 | | - $text = SFFormPrinter::hiddenFieldHTML($template_name, $field_name, $cur_value); |
492 | | - } elseif ($autocomplete_category != null) { |
493 | | - if ($size == null) $size = 35; |
494 | | - $text = SFFormPrinter::textEntryWithAutocompleteHTML($size, $template_name, $field_name, $instance_num, $autocomplete_category, false, $cur_value, $error_str); |
495 | | - } elseif ($input_type == 'text') { |
496 | | - if ($size == null) $size = 35; |
497 | | - $text = SFFormPrinter::textEntryHTML($size, $template_name, $field_name, $cur_value, $error_str); |
498 | | - } elseif ($input_type == 'textarea') { |
499 | | - if ($num_rows == null) $num_rows = 4; |
500 | | - if ($num_cols == null) $num_cols = 40; |
501 | | - $text = SFFormPrinter::textAreaHTML($num_rows, $num_cols, $template_name, $field_name, $cur_value, $error_str); |
502 | | - } elseif ($input_type == 'date') { |
503 | | - $text = SFFormPrinter::dateEntryHTML($template_name, $field_name, $cur_value, $error_str); |
504 | | - } elseif ($input_type == 'checkbox') { |
505 | | - $text = SFFormPrinter::checkboxHTML($template_name, $field_name, $cur_value, $error_str); |
506 | | - } elseif ($template_field->attr_or_rel == "relation") { |
507 | | - if ($size == null) $size = 35; |
508 | | - if ($no_autocomplete) { |
509 | | - $text = SFFormPrinter::textEntryHTML($size, $template_name, $field_name, $cur_value, $error_str); |
510 | | - } else { |
511 | | - $text = SFFormPrinter::textEntryWithAutocompleteHTML($size, $template_name, $field_name, $instance_num, $template_field->semantic_field, true, $cur_value, $error_str); |
512 | | - } |
513 | | - } else { // input type not defined in form, and not a relation |
514 | | - $attr_type = $template_field->attribute_type; |
515 | | - if ($attr_type == $smwgContLang->smwDatatypeLabels['smw_enum']) { |
516 | | - // prepend the "None" option if it's not a mandatory field |
517 | | - $include_none = ! $is_mandatory; |
518 | | - $text = SFFormPrinter::dropdownHTML($template_name, $field_name, $template_field->possible_values, $include_none, $cur_value, $error_str); |
519 | | - } elseif ($attr_type == $smwgContLang->smwDatatypeLabels['smw_datetime']) { |
520 | | - $text = SFFormPrinter::dateEntryHTML($template_name, $field_name, $cur_value, $error_str); |
521 | | - } elseif ($attr_type == $smwgContLang->smwDatatypeLabels['smw_float'] || $attr_type == $smwgContLang->smwDatatypeLabels['smw_int']) { |
522 | | - if ($size == null) $size = 10; |
523 | | - $text = SFFormPrinter::textEntryHTML($size, $template_name, $field_name, $cur_value, $error_str); |
524 | | - } elseif ($attr_type == $smwgContLang->smwDatatypeLabels['smw_url']) { |
525 | | - if ($size == null) $size = 100; |
526 | | - $text = SFFormPrinter::textEntryHTML($size, $template_name, $field_name, $cur_value, $error_str); |
527 | | - } elseif ($attr_type == $smwgContLang->smwDatatypeLabels['smw_bool']) { |
528 | | - $text = SFFormPrinter::checkboxHTML($template_name, $field_name, $cur_value, $error_str); |
529 | | - } else { // String or anything else |
530 | | - if ($size == null) $size = 35; |
531 | | - $text = SFFormPrinter::textEntryHTML($size, $template_name, $field_name, $cur_value, $error_str); |
532 | | - } |
533 | | - } |
534 | | - return $text; |
| 558 | + |
| 559 | + if ($template_field->is_hidden) { |
| 560 | + $text = SFFormPrinter::hiddenFieldHTML($template_field->input_name, $cur_value); |
| 561 | + } elseif ($template_field->autocomplete_category != null) { |
| 562 | + $size = $template_field->size; |
| 563 | + if ($size == null) $size = 35; |
| 564 | + $text = SFFormPrinter::textEntryWithAutocompleteHTML($size, $template_field->input_name, $template_field->part_of_multiple, $template_field->autocomplete_category, false, $cur_value); |
| 565 | + } elseif ($template_field->input_type == 'text') { |
| 566 | + $size = $template_field->size; |
| 567 | + if ($size == null) $size = 35; |
| 568 | + $text = SFFormPrinter::textEntryHTML($size, $template_field->input_name, $cur_value); |
| 569 | + } elseif ($template_field->input_type == 'textarea') { |
| 570 | + $num_rows = $template_field->num_rows; |
| 571 | + if ($num_rows == null) $num_rows = 4; |
| 572 | + $num_cols = $template_field->num_cols; |
| 573 | + if ($num_cols == null) $num_cols = 40; |
| 574 | + $text = SFFormPrinter::textAreaHTML($num_rows, $num_cols, $template_field->input_name, $cur_value); |
| 575 | + } elseif ($template_field->input_type == 'date') { |
| 576 | + $text = SFFormPrinter::dateEntryHTML($template_field->input_name, $cur_value); |
| 577 | + } elseif ($template_field->input_type == 'checkbox') { |
| 578 | + $text = SFFormPrinter::checkboxHTML($template_field->input_name, $cur_value); |
| 579 | + } elseif ($template_field->attr_or_rel == "relation") { |
| 580 | + $size = $template_field->size; |
| 581 | + if ($size == null) $size = 35; |
| 582 | + if ($template_field->no_autocomplete) { |
| 583 | + $text = SFFormPrinter::textEntryHTML($size, $template_field->input_name, $cur_value); |
| 584 | + } else { |
| 585 | + $text = SFFormPrinter::textEntryWithAutocompleteHTML($size, $template_field->input_name, $template_field->part_of_multiple, $template_field->semantic_field, true, $cur_value); |
| 586 | + } |
| 587 | + } else { // input type not defined in form, and not a relation |
| 588 | + $attr_type = $template_field->attribute_type; |
| 589 | + $size = $template_field->size; |
| 590 | + if ($attr_type == $smwgContLang->smwDatatypeLabels['smw_enum']) { |
| 591 | + // prepend the "None" option if it's not a mandatory field |
| 592 | + $include_none = ! $template_field->is_mandatory; |
| 593 | + $text = SFFormPrinter::dropdownHTML($template_field->input_name, $template_field->possible_values, $include_none, $cur_value); |
| 594 | + } elseif ($attr_type == $smwgContLang->smwDatatypeLabels['smw_datetime']) { |
| 595 | + $text = SFFormPrinter::dateEntryHTML($template_field->input_name, $cur_value); |
| 596 | + } elseif ($attr_type == $smwgContLang->smwDatatypeLabels['smw_float'] || $attr_type == $smwgContLang->smwDatatypeLabels['smw_int']) { |
| 597 | + if ($size == null) $size = 10; |
| 598 | + $text = SFFormPrinter::textEntryHTML($size, $template_field->input_name, $cur_value); |
| 599 | + } elseif ($attr_type == $smwgContLang->smwDatatypeLabels['smw_url']) { |
| 600 | + if ($size == null) $size = 100; |
| 601 | + $text = SFFormPrinter::textEntryHTML($size, $template_field->input_name, $cur_value); |
| 602 | + } elseif ($attr_type == $smwgContLang->smwDatatypeLabels['smw_bool']) { |
| 603 | + $text = SFFormPrinter::checkboxHTML($template_field->input_name, $cur_value); |
| 604 | + } else { // String or anything else |
| 605 | + if ($size == null) $size = 35; |
| 606 | + $text = SFFormPrinter::textEntryHTML($size, $template_field->input_name, $cur_value); |
| 607 | + } |
| 608 | + } |
| 609 | + return $text; |
535 | 610 | } |
536 | 611 | |
537 | 612 | function createAutocompleteValuesString($field_name, $is_relation) { |
— | — | @@ -542,11 +617,13 @@ |
543 | 618 | // the query depends on whether this field is a relation or a category |
544 | 619 | if ($is_relation) { |
545 | 620 | $conditions = "relation_title = '$field_name'"; |
| 621 | + $sql_options['ORDER BY'] = 'object_title'; |
546 | 622 | $res = $db->select( $db->tableName('smw_relations'), |
547 | 623 | 'DISTINCT object_title', |
548 | 624 | $conditions, $fname, $sql_options); |
549 | 625 | } else { |
550 | 626 | $conditions = "cl_from = page_id AND cl_to = '$field_name'"; |
| 627 | + $sql_options['ORDER BY'] = 'page_title'; |
551 | 628 | $res = $db->select( $db->tableNames('categorylinks', 'page'), |
552 | 629 | 'page_title', |
553 | 630 | $conditions, $fname, $sql_options); |
— | — | @@ -563,30 +640,24 @@ |
564 | 641 | return $array_str; |
565 | 642 | } |
566 | 643 | |
567 | | - function textEntryHTML($size, $template_name, $field_name, $cur_value, $error_str) { |
| 644 | + function textEntryHTML($size, $input_name, $cur_value) { |
568 | 645 | global $gTabIndex, $gDisabledText; |
569 | | - $gTabIndex++; |
| 646 | + $input_id = "input_$gTabIndex"; |
| 647 | + $info_id = "info_$gTabIndex"; |
570 | 648 | |
571 | | - if ($template_name == null || $template_name == '') |
572 | | - $input_name = $field_name; |
573 | | - else |
574 | | - $input_name = $template_name . '[' . $field_name . ']'; |
575 | 649 | $text =<<<END |
576 | | - <input tabindex="$gTabIndex" class="createboxInput" name="$input_name" type="text" |
| 650 | + <input id="$input_id" tabindex="$gTabIndex" class="createboxInput" name="$input_name" type="text" |
577 | 651 | value="$cur_value" size="$size" $gDisabledText/> |
| 652 | + <span id="$info_id" class="error_message"></span> |
578 | 653 | |
579 | 654 | END; |
580 | | - if ($error_str) { |
581 | | - $text .= " <font color=\"red\">$error_str</font>\n"; |
582 | | - } |
583 | 655 | return $text; |
584 | 656 | } |
585 | 657 | |
586 | | - function dropdownHTML($template_name, $field_name, $possible_values, $include_none, $cur_value, $error_str) { |
| 658 | + function dropdownHTML($input_name, $possible_values, $include_none, $cur_value) { |
587 | 659 | global $gTabIndex, $gDisabledText; |
588 | | - $gTabIndex++; |
589 | 660 | |
590 | | - $text = ' <select tabindex="' . $gTabIndex . '" name="' . $template_name . '[' . $field_name . ']" ' . $gDisabledText . '>'; |
| 661 | + $text = ' <select tabindex="' . $gTabIndex . '" name="' . $input_name . '" ' . $gDisabledText . '>'; |
591 | 662 | if ($include_none) |
592 | 663 | $text .= " <option value=\"\">[None]</option>\n"; |
593 | 664 | foreach ($possible_values as $possible_value) { |
— | — | @@ -594,37 +665,27 @@ |
595 | 666 | if ($possible_value == $cur_value) {$text .= " selected=\"selected\""; } |
596 | 667 | $text .= ">$possible_value</option>\n"; |
597 | 668 | } |
598 | | - $text .= " </select>\n"; |
599 | | - if ($error_str) |
600 | | - $text .= " <font color=\"red\">$error_str</font>\n"; |
| 669 | + $text .=<<<END |
| 670 | + </select> |
| 671 | + <span id="$info_id" class="error_message"></span> |
| 672 | + |
| 673 | +END; |
601 | 674 | return $text; |
602 | 675 | } |
603 | 676 | |
604 | | - function textEntryWithAutocompleteHTML($size, $template_name, $field_name, $instance_num, $semantic_field_name, $is_relation, $cur_value, $error_str) { |
| 677 | + function textEntryWithAutocompleteHTML($size, $input_name, $part_of_multiple, $semantic_field_name, $is_relation, $cur_value) { |
605 | 678 | global $gTabIndex, $gDisabledText; |
606 | 679 | $gTabIndex++; |
607 | 680 | |
608 | | - $input_id = $template_name . "_" . $field_name . "_input"; |
609 | | - $div_name = $template_name . "_" . $field_name . "_div"; |
610 | | - // add instance num to the HTML labels if it's the second or higher, to |
611 | | - // guarantee uniqueness of name; autocompletion fails on IE otherwise |
612 | | - if ($instance_num > 1) { |
613 | | - $input_id .= "_" . $instance_num; |
614 | | - $div_name .= "_" . $instance_num; |
615 | | - } |
616 | | - $input_name = $template_name . '[' . $field_name . ']'; |
617 | | - |
| 681 | + $input_id = "input_" . $gTabIndex; |
| 682 | + $info_id = "info_" . $gTabIndex; |
| 683 | + $div_name = "div_" . $gTabIndex; |
618 | 684 | $options_str = SFFormPrinter::createAutocompleteValuesString(str_replace(' ', '_', $semantic_field_name), $is_relation); |
619 | 685 | $text =<<<END |
620 | | - <input tabindex="$gTabIndex" id="$input_id" autocomplete="off" class="createboxInput" name="$input_name" type="text" |
621 | | - value="" size="$size" $gDisabledText/> |
622 | | - |
623 | | -END; |
624 | | - if ($error_str) { |
625 | | - $text .= " <font color=\"red\">$error_str</font>"; |
626 | | - } |
627 | | - $text .=<<<END |
628 | | - <div class="page_name_auto_complete" id="$div_name" style="display:none"></div> |
| 686 | + <input tabindex="$gTabIndex" id="$input_id" name="$input_name" type="text" |
| 687 | + value="" size="$size" $gDisabledText/> |
| 688 | + <span id="$info_id" class="error_message"></span> |
| 689 | + <div class="page_name_auto_complete" id="$div_name" style="display:none"></div> |
629 | 690 | <script type="text/javascript"> |
630 | 691 | new Autocompleter.Local('$input_id', '$div_name', $options_str, {}); |
631 | 692 | |
— | — | @@ -636,29 +697,23 @@ |
637 | 698 | return $text; |
638 | 699 | } |
639 | 700 | |
640 | | - function textAreaHTML($rows, $cols, $template_name, $field_name, $cur_value, $error_str) { |
| 701 | + function textAreaHTML($rows, $cols, $input_name, $cur_value) { |
641 | 702 | global $gTabIndex, $gDisabledText; |
642 | | - $gTabIndex++; |
| 703 | + $input_id = "input_$gTabIndex"; |
| 704 | + $info_id = "info_$gTabIndex"; |
643 | 705 | |
644 | | - if ($template_name == null) { |
645 | | - $input_name = $field_name; |
646 | | - } else { |
647 | | - $input_name = $template_name . '[' . $field_name . ']'; |
648 | | - } |
649 | 706 | $text =<<<END |
650 | | - <textarea tabindex="$gTabIndex" name="$input_name" rows=$rows cols=$cols $gDisabledText/>$cur_value</textarea> |
| 707 | + <textarea tabindex="$gTabIndex" id="$input_id" name="$input_name" rows=$rows cols=$cols $gDisabledText/>$cur_value</textarea> |
| 708 | + <span id="$info_id" class="error_message"></span> |
651 | 709 | |
652 | 710 | END; |
653 | | - if ($error_str) |
654 | | - $text .= " <font color=\"red\">$error_str</font>\n"; |
655 | 711 | return $text; |
656 | 712 | } |
657 | 713 | |
658 | | - function monthDropdownHTML($cur_month, $template_name, $index) { |
| 714 | + function monthDropdownHTML($cur_month, $input_name) { |
659 | 715 | global $gTabIndex, $gDisabledText; |
660 | | - $gTabIndex++; |
661 | 716 | |
662 | | - $text = ' <select tabindex="' . $gTabIndex . '" name="' . $template_name . '[' . $index . "][month]\" $gDisabledText>\n"; |
| 717 | + $text = ' <select tabindex="' . $gTabIndex . '" id="input_' . $gTabIndex . '" name="' . $input_name . "[month]\" $gDisabledText>\n"; |
663 | 718 | $month_names = array( |
664 | 719 | wfMsgForContent('sf_january'), |
665 | 720 | wfMsgForContent('sf_february'), |
— | — | @@ -682,9 +737,8 @@ |
683 | 738 | return $text; |
684 | 739 | } |
685 | 740 | |
686 | | - function dateEntryHTML($template_name, $index, $date, $error_str) { |
| 741 | + function dateEntryHTML($input_name, $date) { |
687 | 742 | global $gTabIndex, $gDisabledText; |
688 | | - $gTabIndex++; |
689 | 743 | |
690 | 744 | if ($date) { |
691 | 745 | // can show up here either as an array or a string, depending on |
— | — | @@ -705,25 +759,21 @@ |
706 | 760 | $month = $cur_date[month]; |
707 | 761 | $day = null; // no need for day |
708 | 762 | } |
709 | | - $text .= SFFormPrinter::monthDropdownHTML($month, $template_name, $index); |
710 | | - $gTabIndex++; |
711 | | - $text .= ' <input tabindex="' . $gTabIndex . '" name="' . $template_name . '[' . $index . '][day]" type="text" value="' . $day . '" size="2"/ ' . $gDisabledText . '>' . "\n"; |
712 | | - $gTabIndex++; |
713 | | - $text .= ' <input tabindex="' . $gTabIndex . '" name="' . $template_name . '[' . $index . '][year]" type="text" value="' . $year . '" size="4"/ ' . $gDisabledText . '>' . "\n"; |
714 | | - if ($error_str) { |
715 | | - $text .= " <font color=\"red\">$error_str</font>\n"; |
716 | | - } |
| 763 | + $text .= SFFormPrinter::monthDropdownHTML($month, $input_name); |
| 764 | + $text .= ' <input tabindex="' . $gTabIndex . '" id="input_' . $gTabIndex . '" name="' . $input_name . '[day]" type="text" value="' . $day . '" size="2"/ ' . $gDisabledText . '>' . "\n"; |
| 765 | + $text .= ' <input tabindex="' . $gTabIndex . '" id="input_' . $gTabIndex . '" name="' . $input_name . '[year]" type="text" value="' . $year . '" size="4"/ ' . $gDisabledText . '>' . "\n"; |
| 766 | + $info_id = "info_$gTabIndex"; |
| 767 | + $text .= " <span id=\"$info_id\" class=\"error_message\"></span>"; |
717 | 768 | return $text; |
718 | 769 | } |
719 | 770 | |
720 | | - function radioButtonHTML($template_name, $field_name, $cur_value, $options_array) { |
| 771 | + function radioButtonHTML($input_name, $cur_value, $options_array) { |
721 | 772 | global $gTabIndex, $gDisabledText; |
722 | | - $gTabIndex++; |
723 | 773 | |
724 | 774 | if ($title) |
725 | 775 | $text .= " <strong>$title:</strong>\n"; |
726 | 776 | foreach ($options_array as $i => $option) { |
727 | | - $text .= ' <input type="radio" tabindex="' . $gTabIndex . '" name="' . $template_name . '[' . $field_name . ']" value="$option"'; |
| 777 | + $text .= ' <input type="radio" tabindex="' . $gTabIndex . '" name="' . $input_name . '" value="' . $option . '"'; |
728 | 778 | if ($cur_value == $option || (! $cur_value && $i == 0)) |
729 | 779 | $text .= " checked"; |
730 | 780 | $text .= " $gDisabledText/> $option\n"; |
— | — | @@ -731,9 +781,9 @@ |
732 | 782 | return $text; |
733 | 783 | } |
734 | 784 | |
735 | | - function checkboxHTML($template_name, $field_name, $cur_value, $error_str) { |
| 785 | + function checkboxHTML($input_name, $cur_value) { |
736 | 786 | global $gTabIndex, $gDisabledText; |
737 | | - $gTabIndex++; |
| 787 | + $info_id = "info_$gTabIndex"; |
738 | 788 | |
739 | 789 | // can show up here either as an array or a string, depending on |
740 | 790 | // whether it came from user input or a wiki page |
— | — | @@ -748,23 +798,16 @@ |
749 | 799 | $checked_str = ""; |
750 | 800 | } |
751 | 801 | } |
752 | | - $input_name = $template_name . '[' . $field_name . ']'; |
753 | 802 | $text =<<<END |
754 | 803 | <input name="{$input_name}[is_checkbox]" type="hidden" value="true" /> |
755 | | - <input name="{$input_name}[value]" type="checkbox" tabindex="$gTabIndex " $checked_str $gDisabledText/> |
| 804 | + <input id="input_$gTabIndex" name="{$input_name}[value]" type="checkbox" tabindex="$gTabIndex " $checked_str $gDisabledText/> |
| 805 | + <span id="$info_id" class="error_message"></span> |
756 | 806 | |
757 | 807 | END; |
758 | | - if ($error_str) { |
759 | | - $text .= " <font color=\"red\">$error_str</font>\n"; |
760 | | - } |
761 | 808 | return $text; |
762 | 809 | } |
763 | 810 | |
764 | | - function hiddenFieldHTML($template_name, $field_name, $cur_value) { |
765 | | - if ($template_name == null || $template_name == '') |
766 | | - $input_name = $field_name; |
767 | | - else |
768 | | - $input_name = $template_name . '[' . $field_name . ']'; |
| 811 | + function hiddenFieldHTML($input_name, $cur_value) { |
769 | 812 | $text =<<<END |
770 | 813 | <input type="hidden" name="$input_name" value="$cur_value" /> |
771 | 814 | |