r79270 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r79269‎ | r79270 | r79271 >
Date:17:28, 30 December 2010
Author:foxtrott
Status:deferred (Comments)
Tags:
Comment:
major rework of extension

* introduced new input type timepicker
* introduced new input type menuselect
* cleanup of file structure
* fix for reported version number (fix r75634)
* fix bug 25917
* fix bug 26289

open issues:
* MW 1.15 compatibility
* MW 1.18 compatibility
* does not work with "multiple" forms
* does not support validation
Modified paths:
  • /trunk/extensions/SemanticFormsInputs/README (modified) (history)
  • /trunk/extensions/SemanticFormsInputs/SFI_Inputs.php (modified) (history)
  • /trunk/extensions/SemanticFormsInputs/SFI_Settings.php (modified) (history)
  • /trunk/extensions/SemanticFormsInputs/SemanticFormsInputs.php (modified) (history)
  • /trunk/extensions/SemanticFormsInputs/libs (added) (history)
  • /trunk/extensions/SemanticFormsInputs/libs/datepicker.js (added) (history)
  • /trunk/extensions/SemanticFormsInputs/libs/menuselect.js (added) (history)
  • /trunk/extensions/SemanticFormsInputs/libs/regexp.js (added) (history)
  • /trunk/extensions/SemanticFormsInputs/libs/timepicker.js (added) (history)
  • /trunk/extensions/SemanticFormsInputs/nbproject (added) (history)
  • /trunk/extensions/SemanticFormsInputs/nbproject/project.properties (added) (history)
  • /trunk/extensions/SemanticFormsInputs/nbproject/project.xml (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/SFI_Menuselect.css (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/SFI_Timepicker.css (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/DatePickerButton.gif (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/DatePickerButtonDisabled.gif (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/DatePickerResetButton.gif (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/DatePickerResetButtonDisabled.gif (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/MenuSelectArrow.gif (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/TimePickerButton.gif (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/TimePickerButtonDisabled.gif (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/TimePickerResetButton.gif (added) (history)
  • /trunk/extensions/SemanticFormsInputs/skins/images/TimePickerResetButtonDisabled.gif (added) (history)

Diff [purge]

Index: trunk/extensions/SemanticFormsInputs/SemanticFormsInputs.php
@@ -4,8 +4,8 @@
55 *
66 * @author Stephan Gambke
77 * @author Sanyam Goyal
8 - * @version 0.3.1
9 - */
 8+ * @version 0.4 alpha
 9+ */
1010
1111 if ( !defined( 'MEDIAWIKI' ) ) {
1212 die( 'This file is a MediaWiki extension, it is not a valid entry point.' );
@@ -15,7 +15,7 @@
1616 die( 'This is a Semantic Forms extension. You need to install Semantic Forms first.' );
1717 }
1818
19 -define( 'SFI_VERSION', '0.7.3 alpha' );
 19+define( 'SFI_VERSION', '0.4 alpha' );
2020
2121 // create and initialize settings
2222 $sfigSettings = new SFISettings();
@@ -30,10 +30,11 @@
3131 'version' => SFI_VERSION,
3232 );
3333
 34+$dir = dirname( __FILE__ );
 35+
3436 // load user settings
35 -require_once( 'SFI_Settings.php' );
 37+require_once( $dir. '/SFI_Settings.php' );
3638
37 -$dir = dirname( __FILE__ );
3839 $wgExtensionMessagesFiles['SemanticFormsInputs'] = $dir . '/SemanticFormsInputs.i18n.php';
3940 $wgExtensionFunctions[] = "wfSFISetup";
4041 $wgAutoloadClasses['SFIInputs'] = $dir . '/SFI_Inputs.php';
@@ -71,6 +72,10 @@
7273 $sfgFormPrinter->setInputTypeHook( 'regexp', array( 'SFIInputs', 'regexpHTML' ), array() );
7374 $sfgFormPrinter->setInputTypeHook( 'datepicker', array( 'SFIInputs', 'jqDatePickerHTML' ), array() );
7475 $sfgFormPrinter->setInputTypeHook( 'simpledatepicker', array( 'SFIInputs', 'jqDatePickerHTML' ), array() );
 76+ $sfgFormPrinter->setInputTypeHook( 'timepicker', array( 'SFIInputs', 'timepickerHTML' ), array() );
 77+// $sfgFormPrinter->setInputTypeHook( 'wysiwyg', array( 'SFIInputs', 'wysiwygHTML' ), array() );
 78+ $sfgFormPrinter->setInputTypeHook( 'menuselect', array( 'SFIInputs', 'menuselectHTML' ), array() );
7579
76 - $wgOut->addInlineScript( 'sfiElements = new Object();' );
 80+ // TODO: obsolete as of MW 1.16, remove around 1.18 or so
 81+ wfLoadExtensionMessages( 'SemanticFormsInputs' );
7782 }
Index: trunk/extensions/SemanticFormsInputs/nbproject/project.properties
@@ -0,0 +1,7 @@
 2+include.path=${php.global.include.path}
 3+php.version=PHP_5
 4+source.encoding=UTF-8
 5+src.dir=.
 6+tags.asp=false
 7+tags.short=true
 8+web.root=.
Index: trunk/extensions/SemanticFormsInputs/nbproject/project.xml
@@ -0,0 +1,9 @@
 2+<?xml version="1.0" encoding="UTF-8"?>
 3+<project xmlns="http://www.netbeans.org/ns/project/1">
 4+ <type>org.netbeans.modules.php.project</type>
 5+ <configuration>
 6+ <data xmlns="http://www.netbeans.org/ns/php-project/1">
 7+ <name>SemanticFormsInputs</name>
 8+ </data>
 9+ </configuration>
 10+</project>
Property changes on: trunk/extensions/SemanticFormsInputs/nbproject
___________________________________________________________________
Added: svn:ignore
111 + private
Index: trunk/extensions/SemanticFormsInputs/SFI_Settings.php
@@ -3,34 +3,34 @@
44 * Settings for the Semantic Forms Inputs extension.
55 *
66 * @author Stephan Gambke
7 - * @version 0.3.1
 7+ * @version 0.4 alpha
88 *
99 * To change the default settings you can uncomment (or copy) the
1010 * examples here and adjust them to your needs. You may as well
1111 * include them in your LocalSettings.php.
1212 */
1313
14 -# # #
 14+##
1515 # This is the path to your installation of Semantic Forms Inputs as
1616 # seen from the web. No final slash.
17 -# #
 17+#
1818 $sfigSettings->scriptPath = $wgScriptPath . '/extensions/SemanticFormsInputs';
1919
20 -# # # Date Picker Settings
 20+## Date Picker Settings
2121
22 -# # #
 22+##
2323 # This is the first selectable date (format yyyy/mm/dd)
2424 # Sample value: '2005/01/01'
25 -# #
 25+#
2626 $sfigSettings->datePickerFirstDate = null;
2727
28 -# # #
 28+##
2929 # This is the last selectable date (format yyyy/mm/dd)
3030 # Sample value: '2015/31/12'
31 -# #
 31+#
3232 $sfigSettings->datePickerLastDate = null;
3333
34 -# # #
 34+##
3535 # The date format string used for the user input.
3636 # The date sent back to the form is fixed to yyyy/mm/dd
3737 # (that is, yy/mm/dd in the format code below).
@@ -71,63 +71,91 @@
7272 # TICKS - '!'
7373 # TIMESTAMP - '@'
7474 # W3C - 'yy-mm-dd' (Same as ISO 8601)
75 -# #
 75+#
7676 $sfigSettings->datePickerDateFormat = 'SHORT';
7777
78 -# # #
 78+##
7979 # This determines the start of the week in the display.
8080 # Set it to: 0 (Zero) for Sunday, 1 (One) for Monday etc.
8181 # If set to null the day is localized to the wiki user language
8282 # Sample value: 1
83 -# #
 83+#
8484 $sfigSettings->datePickerWeekStart = null;
8585
86 -# # #
 86+##
8787 # This determines if the number of the week shall be shown.
88 -# #
 88+#
8989 $sfigSettings->datePickerShowWeekNumbers = false;
9090
91 -# # #
 91+##
9292 # This determines if the input field shall be disabled. The user can
9393 # only set the date via the datepicker in this case.
94 -# #
 94+#
9595 $sfigSettings->datePickerDisableInputField = false;
9696
97 -# # #
 97+##
9898 # This determines if a reset button shall be shown. This is the only
9999 # way to erase the input field if it is disabled for direct input.
100 -# #
 100+#
101101 $sfigSettings->datePickerShowResetButton = false;
102102
103 -# # #
 103+##
104104 # This is a string of disabled days of the week, i.e. days the user can not
105105 # pick. The days must be given as comma-separated list of numbers starting
106106 # with 0 for Sunday.
107107 # Sample value: "6,0"
108 -# #
 108+#
109109 $sfigSettings->datePickerDisabledDaysOfWeek = null;
110110
111 -# # #
 111+##
112112 # This is a string of highlighted days of the week. The days must be given as
113113 # comma-separated list of numbers starting with 0 for Sunday.
114114 # Sample value: "6,0"
115 -# #
 115+#
116116 $sfigSettings->datePickerHighlightedDaysOfWeek = null;
117117
118 -# # #
 118+##
119119 # This is a string of disabled dates, i.e. days the user cannot pick. The
120120 # days must be given as comma-separated list of dates or date ranges. The
121121 # format for days is yyyy/mm/dd, for date ranges use yyyy/mm/dd-yyyy/mm/dd.
122122 # Spaces are permissible.
123123 # Sample value: "2010/12/25 - 2011/01/06, 2011/05/01"
124 -# #
 124+#
125125 $sfigSettings->datePickerDisabledDates = null;
126126
127 -# # #
 127+##
128128 # This is a string of highlighted dates. The days must be given as
129129 # comma-separated list of dates or date ranges. The format for days is
130130 # yyyy/mm/dd, for date ranges use yyyy/mm/dd-yyyy/mm/dd. Spaces are
131131 # permissible.
132132 # Sample value: "2010/12/25 - 2011/01/06, 2011/05/01"
133 -# #
 133+#
134134 $sfigSettings->datePickerHighlightedDates = null;
 135+
 136+
 137+## Time Picker Settings
 138+
 139+##
 140+# This is the first selectable time (format hh:mm)
 141+# Sample value: '00:00'
 142+#
 143+$sfigSettings->timePickerMinTime = null;
 144+
 145+##
 146+# This is the last selectable time (format hh:mm)
 147+# Sample value: '24:00'
 148+#
 149+$sfigSettings->timePickerMaxTime = null;
 150+
 151+##
 152+# This determines if the input field shall be disabled. The user can
 153+# only set the time via the timepicker in this case.
 154+#
 155+$sfigSettings->timePickerDisableInputField = false;
 156+
 157+##
 158+# This determines if a reset button shall be shown. This is the only
 159+# way to erase the input field if it is disabled for direct input.
 160+#
 161+$sfigSettings->timePickerShowResetButton = false;
 162+
Index: trunk/extensions/SemanticFormsInputs/skins/SFI_Timepicker.css
@@ -0,0 +1,35 @@
 2+/**
 3+ * Style sheet for the input type timepicker.
 4+ *
 5+ * @author Stephan Gambke
 6+ * @version 0.4 alpha
 7+ */
 8+
 9+.SFI_timepicker {
 10+ display: block;
 11+ position: absolute;
 12+ cursor: default;
 13+}
 14+
 15+.SFI_timepicker ul { /* hours and minutes lists */
 16+ margin: 0px;
 17+ padding: 0px;
 18+ list-style: none;
 19+ position: absolute;
 20+}
 21+
 22+.SFI_timepicker ul ul { /* minutes lists only */
 23+ margin-left: 24px;
 24+ margin-right: 24px;
 25+ margin-top: -22px;
 26+}
 27+
 28+
 29+.SFI_timepicker li { /* hours and minutes entries */
 30+ margin: 1px 0px;
 31+ padding: 0px;
 32+ text-align: center;
 33+ line-height: 22px;
 34+ width: 22px;
 35+}
 36+
Property changes on: trunk/extensions/SemanticFormsInputs/skins/SFI_Timepicker.css
___________________________________________________________________
Added: svn:eol-style
137 + native
Index: trunk/extensions/SemanticFormsInputs/skins/images/TimePickerResetButton.gif
Cannot display: file marked as a binary type.
svn:mime-type = image/gif
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/TimePickerResetButton.gif
___________________________________________________________________
Added: svn:mime-type
238 + image/gif
Index: trunk/extensions/SemanticFormsInputs/skins/images/DatePickerButtonDisabled.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/DatePickerButtonDisabled.gif
___________________________________________________________________
Added: svn:mime-type
339 + application/octet-stream
Index: trunk/extensions/SemanticFormsInputs/skins/images/MenuSelectArrow.gif
Cannot display: file marked as a binary type.
svn:mime-type = image/gif
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/MenuSelectArrow.gif
___________________________________________________________________
Added: svn:mime-type
440 + image/gif
Index: trunk/extensions/SemanticFormsInputs/skins/images/TimePickerButtonDisabled.gif
Cannot display: file marked as a binary type.
svn:mime-type = image/gif
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/TimePickerButtonDisabled.gif
___________________________________________________________________
Added: svn:mime-type
541 + image/gif
Index: trunk/extensions/SemanticFormsInputs/skins/images/DatePickerResetButtonDisabled.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/DatePickerResetButtonDisabled.gif
___________________________________________________________________
Added: svn:mime-type
642 + application/octet-stream
Index: trunk/extensions/SemanticFormsInputs/skins/images/TimePickerResetButtonDisabled.gif
Cannot display: file marked as a binary type.
svn:mime-type = image/gif
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/TimePickerResetButtonDisabled.gif
___________________________________________________________________
Added: svn:mime-type
743 + image/gif
Index: trunk/extensions/SemanticFormsInputs/skins/images/DatePickerButton.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/DatePickerButton.gif
___________________________________________________________________
Added: svn:mime-type
844 + application/octet-stream
Index: trunk/extensions/SemanticFormsInputs/skins/images/TimePickerButton.gif
Cannot display: file marked as a binary type.
svn:mime-type = image/gif
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/TimePickerButton.gif
___________________________________________________________________
Added: svn:mime-type
945 + image/gif
Index: trunk/extensions/SemanticFormsInputs/skins/images/DatePickerResetButton.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticFormsInputs/skins/images/DatePickerResetButton.gif
___________________________________________________________________
Added: svn:mime-type
1046 + application/octet-stream
Index: trunk/extensions/SemanticFormsInputs/skins/SFI_Menuselect.css
@@ -0,0 +1,60 @@
 2+/**
 3+ * Style sheet for the input type menuselect.
 4+ *
 5+ * @author Stephan Gambke
 6+ * @version 0.4 alpha
 7+ */
 8+
 9+.SFI_menuselect {
 10+ visibility: hidden; /* will be shown by JS when setup is finished*/
 11+ display: block;
 12+ cursor: default;
 13+ position: absolute;
 14+}
 15+
 16+.SFI_menuselect a {
 17+ cursor: default;
 18+}
 19+
 20+.SFI_menuselect ul { /* all lists */
 21+ margin: 0px;
 22+ padding: 0px;
 23+ /*margin: -20px;
 24+ padding: 20px;*/
 25+ list-style: none;
 26+ position: absolute;
 27+ display: inline;
 28+}
 29+
 30+.SFI_menuselect ul ul { /* sub-item lists only */
 31+ margin-left: 2px;
 32+ margin-right: 2px;
 33+ margin-top: -2px;
 34+ /*margin-left: -18px;
 35+ margin-right: -18px;
 36+ margin-top: -22px;*/
 37+}
 38+
 39+
 40+.SFI_menuselect li { /* all entries */
 41+ margin: 1px 0px;
 42+ padding: 0px 0px;
 43+ text-align: left;
 44+ /*position: static;*/
 45+ /*display:inline;*/
 46+ /*min-width: 100px;*/
 47+}
 48+
 49+.SFI_menuselect li>span { /* all entries */
 50+ display:inline-block;
 51+ width:100%;
 52+}
 53+
 54+.SFI_menuselect li>span>div.cont {
 55+ padding:0px 2px;
 56+}
 57+
 58+.SFI_menuselect li>span>div.arrow {
 59+ float:right;
 60+}
 61+
Property changes on: trunk/extensions/SemanticFormsInputs/skins/SFI_Menuselect.css
___________________________________________________________________
Added: svn:eol-style
162 + native
Index: trunk/extensions/SemanticFormsInputs/SFI_Inputs.php
@@ -5,7 +5,7 @@
66 * @author Stephan Gambke
77 * @author Sanyam Goyal
88 * @author Yaron Koren
9 - * @version 0.3.1
 9+ * @version 0.4 alpha
1010 *
1111 */
1212
@@ -16,89 +16,135 @@
1717 class SFIInputs {
1818
1919 /**
20 - * Setup for input type regexp.
21 - * Adds the Javascript code used by all regexp filters.
 20+ * Creates the html text for an input.
 21+ *
 22+ * Common attributes for input types are set according to the parameters.
 23+ * The parameters are the standard parameters set by Semantic Forms'
 24+ * InputTypeHook plus some optional.
 25+ *
 26+ * @param string $cur_value
 27+ * @param string $input_name
 28+ * @param boolean $is_mandatory
 29+ * @param boolean $is_disabled
 30+ * @param array $other_args
 31+ * @param string $input_id (optional)
 32+ * @param int $tabindex (optional)
 33+ * @param string $class
 34+ * @return string the html text of an input element
 35+ */
 36+ static private function textHTML ( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args, $input_id = null, $tabindex = null, $class = "" ) {
 37+
 38+ global $sfgFieldNum, $sfgTabIndex;
 39+
 40+ // array of attributes to pass to the input field
 41+ $attribs = array(
 42+ "name" => $input_name,
 43+ "cssclass" => $class,
 44+ "value" => $cur_value,
 45+ "type" => "text"
 46+ );
 47+
 48+ // set size attrib
 49+ if ( array_key_exists( 'size', $other_args ) ) {
 50+ $attribs['size'] = $other_args['size'];
 51+ }
 52+
 53+ // set maxlength attrib
 54+ if ( array_key_exists( 'maxlength', $other_args ) ) {
 55+ $attribs['maxlength'] = $other_args['maxlength'];
 56+ }
 57+
 58+ // modify class attribute for mandatory form fields
 59+ if ( $is_mandatory ) {
 60+ $attribs["cssclass"] .= ' mandatory';
 61+ }
 62+
 63+ // add user class(es) to class attribute of input field
 64+ if ( array_key_exists( 'class', $other_args ) ) {
 65+ $attribs["cssclass"] .= ' ' . $other_args['class'];
 66+ }
 67+
 68+ // set readonly attrib
 69+ if ( $is_disabled ) {
 70+ $attribs["readonly"] = "1";
 71+ }
 72+
 73+ // if no special input id is specified set the Semantic Forms standard
 74+ if ( $input_id == null ) {
 75+ $attribs[ 'id' ] = "input_" . $sfgFieldNum;
 76+ } else {
 77+ $attribs[ 'id' ] = $input_id;
 78+ }
 79+
 80+
 81+ if ( $tabindex == null ) $attribs[ 'tabindex' ] = $sfgTabIndex;
 82+ else $attribs[ 'tabindex' ] = $tabindex;
 83+
 84+ // $html = Html::element( "input", $attribs );
 85+ $html = Xml::element( "input", $attribs );
 86+
 87+ return $html;
 88+
 89+ }
 90+
 91+ /**
 92+ * Setup function for input type regexp.
 93+ *
 94+ * Loads the Javascript code used by all regexp filters.
2295 */
2396 static private function regexpSetup() {
2497
2598 global $wgOut;
 99+ global $sfigSettings;
26100
27101 static $hasRun = false;
28102
29103 if ( !$hasRun ) {
30104 $hasRun = true;
31105
32 - wfLoadExtensionMessages( 'SemanticFormsInputs' );
 106+ $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->scriptPath . '/libs/regexp.js"></script> ' );
33107
34 - $jstext = <<<JAVASCRIPT
35 - function validate_input_with_regexp(input_number, retext, inverse, message, multiple){
36 -
37 - var decoded = jQuery("<div/>").html(retext).text();
38 - var re = new RegExp(decoded);
39 -
40 - if (multiple) {
41 - res = true;
42 - for (i = 1; i <= num_elements; i++) {
43 - field = document.getElementById('input_' + i + "_" + input_number);
44 - if (field) {
45 - match = re.test(field.value);
46 -
47 - if ( !(match && !inverse) && !(!match && inverse) ) {
48 - infobox = document.getElementById('info_' + i + "_" + input_number);
49 - infobox.innerHTML += " " + message;
50 - res=false;
51 - }
52 - }
53 - }
54 - return res;
55 - } else {
56 - field = document.getElementById('input_' + input_number);
57 - match = re.test(field.value);
58 -
59 - if ( (match && !inverse) || (!match && inverse) ) {
60 - return true;
61 - } else {
62 - infobox = document.getElementById('info_' + input_number);
63 - infobox.innerHTML += " " + message;
64 - return false;
65 - }
66 - }
67108 }
68 -JAVASCRIPT;
69 -
70 - $wgOut->addInlineScript( $jstext );
71 - }
72109 }
73110
74111
75112 /**
76113 * Definition of input type "regexp"
77114 *
78 - * Returns an array containing two elements: the html text to be included
79 - * and an empty string (the js code is written directly without piping it
80 - * through SF)
 115+ * Returns an array containing three elements: the html code and the JS code
 116+ * to be included in the page and the name of a JS function to be called to
 117+ * initialize the input.
81118 *
 119+ * These values are all taken from the base input type, the JS for the
 120+ * regexp is written to the code directly.
 121+ *
 122+ * @param string $cur_value current value of this field (which is sometimes null)
 123+ * @param string $input_name HTML name that this input should have
 124+ * @param boolean $is_mandatory indicates whether this field is mandatory for the user
 125+ * @param boolean $is_disabled indicates whether this field is disabled (meaning, the user can't edit)
 126+ * @param array $other_args hash representing all the other properties defined for this input in the form definition
82127 * @return array of two strings
83128 */
84129 static function regexpHTML ( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
85130
86 - global $wgRequest, $wgUser, $wgParser;
87 - global $sfgTabIndex; // used to represent the current tab index in the form
 131+ global $wgOut;
88132 global $sfgFieldNum; // used for setting various HTML IDs
89133 global $sfgJSValidationCalls; // array of Javascript calls to determine if page can be saved
90134 global $sfgFormPrinter;
91135
92136 self::regexpSetup();
93137
94 - // set base type string
 138+ // set base input type
95139 if ( array_key_exists( 'base type', $other_args ) ) {
 140+
96141 $baseType = trim( $other_args['base type'] );
97142 unset( $other_args['base type'] );
98 - }
99 - else $baseType = null;
100143
101 - if ( ! $baseType || ! array_key_exists( $baseType, $sfgFormPrinter->mInputTypeHooks ) )
 144+ // if unknown set default base input type
 145+ if ( ! array_key_exists( $baseType, $sfgFormPrinter->mInputTypeHooks ) )
102146 $baseType = 'text';
 147+ }
 148+ else $baseType = 'text';
103149
104150 // set base prefix string
105151 if ( array_key_exists( 'base prefix', $other_args ) ) {
@@ -127,7 +173,7 @@
128174 $regexp = str_replace( $orChar, '|', trim( $other_args['regexp'] ) );
129175 unset( $other_args['regexp'] );
130176
131 - // check for leading/trailing delimiter and remove it (else dump regexp)
 177+ // check for leading/trailing delimiter and remove it (else reset regexp)
132178 if ( preg_match ( "/^\/.*\/\$/", $regexp ) ) {
133179
134180 $regexp = substr( $regexp, 1, strlen( $regexp ) - 2 );
@@ -145,6 +191,35 @@
146192 }
147193 else $message = wfMsg( 'semanticformsinputs-wrongformat' );
148194
 195+ // sanitize error message and regexp for JS
 196+ $message = Xml::encodeJsVar( $message );
 197+ $regexp = Xml::encodeJsVar( $regexp );
 198+
 199+
 200+ // register this input for validation
 201+ // $sfgJSValidationCalls are sanitized for HTML by SF before output, no htmlspecialchars() here
 202+ if ( array_key_exists( 'part_of_multiple', $other_args ) && $other_args['part_of_multiple'] == 1 ) {
 203+ $jstext = "validate_input_with_regexp($sfgFieldNum, {$regexp}, {$inverseString}, {$message}, true)";
 204+ } else {
 205+ $jstext = "validate_input_with_regexp($sfgFieldNum, {$regexp}, {$inverseString}, {$message}, false)";
 206+ }
 207+
 208+ // register event to validate regexp on submit
 209+ // TODO: Improve so regexp is also validated on preview
 210+ $jstext = <<<JAVASCRIPT
 211+
 212+ jQuery(function($){
 213+ $('#sfForm').submit( function() {
 214+ return $jstext;
 215+ } );
 216+ });
 217+
 218+JAVASCRIPT;
 219+
 220+ //$wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' );
 221+ $wgOut->addInlineScript( $jstext );
 222+
 223+ // create other_args for base input type
149224 $new_other_args = array();
150225
151226 foreach ( $other_args as $key => $value )
@@ -153,6 +228,7 @@
154229 } else
155230 $new_other_args[$key] = $value;
156231
 232+ // setup parameters for base input type
157233 $funcArgs = array();
158234 $funcArgs[] = $cur_value;
159235 $funcArgs[] = $input_name;
@@ -160,31 +236,19 @@
161237 $funcArgs[] = $is_disabled;
162238 $funcArgs[] = $new_other_args;
163239
 240+ // get the input type hooks for the base input type
164241 $hook_values = $sfgFormPrinter->mInputTypeHooks[$baseType];
165242
166 - // sanitize error message and regexp for JS
167 - $message = Xml::encodeJsVar( $message );
168 - $regexp = Xml::encodeJsVar( $regexp );
 243+ // generate html and JS code for base input type and return it
 244+ return call_user_func_array( $hook_values[0], $funcArgs );
169245
170 - // $sfgJSValidationCalls are sanitized for HTML by SF before output, no htmlspecialchars() here
171 - if ( array_key_exists( 'part_of_multiple', $other_args ) && $other_args['part_of_multiple'] == 1 ) {
172 - $sfgJSValidationCalls[] = "validate_input_with_regexp($sfgFieldNum, {$regexp}, {$inverseString}, {$message}, true)";
173 - } else {
174 - $sfgJSValidationCalls[] = "validate_input_with_regexp($sfgFieldNum, {$regexp}, {$inverseString}, {$message}, false)";
175 - }
 246+}
176247
177 - list( $htmltext, $jstext ) = call_user_func_array( $hook_values[0], $funcArgs );
178248
179 - $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' );
180 -
181 - return array( $htmltext, "" );
182 -
183 - }
184 -
185 -
186249 /**
187250 * Setup for input type jqdatepicker.
188 - * Adds the Javascript code used by all date pickers.
 251+ *
 252+ * Adds the Javascript code used by all datepickers.
189253 */
190254 static private function jqDatePickerSetup () {
191255 global $wgOut, $wgLang, $sfgScriptPath;
@@ -198,6 +262,7 @@
199263 $wgOut->addScript( '<script type="text/javascript" src="' . $sfgScriptPath . '/libs/jquery-ui/jquery.ui.datepicker.min.js"></script> ' );
200264 $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->scriptPath . '/libs/datepicker.js"></script> ' );
201265
 266+ // set localized messages (use MW i18n, not jQuery i18n)
202267 $jstext =
203268 "jQuery(function($){\n"
204269 . " $.datepicker.regional['wiki'] = {\n"
@@ -271,15 +336,16 @@
272337 }
273338
274339 /**
275 - * expects a two dimensional array
 340+ * Sort and merge time ranges in an array
 341+ *
 342+ * expects an array of arrays
276343 * the inner arrays must contain two dates representing the start and end
277344 * date of a time range
278345 *
279 - * returns an array with the same structur with the date ranges sorted and
280 - * overlapping ranges merged
 346+ * returns an array of arrays with the date ranges sorted and overlapping
 347+ * ranges merged
281348 *
282 - *
283 - * @param array of arrays of DateTimes
 349+ * @param array $ranges array of arrays of DateTimes
284350 * @return array of arrays of DateTimes
285351 */
286352 static private function sortAndMergeRanges ( $ranges ) {
@@ -287,13 +353,18 @@
288354 // sort ranges, earliest date first
289355 sort( $ranges );
290356
 357+ // stores the start of the current date range
291358 $currmin = FALSE;
 359+
 360+ // stores the date the next ranges start date has to top to not overlap
292361 $nextmin = FALSE;
293362
 363+ // result array
294364 $mergedRanges = array();
295365
296366 foreach ( $ranges as $range ) {
297367
 368+ // ignore empty date ranges
298369 if ( !$range ) continue;
299370
300371 if ( !$currmin ) { // found first valid range
@@ -309,7 +380,7 @@
310381 $range[1]->modify( '+1 day' );
311382 $nextmin = max( $nextmin, $range[1] );
312383
313 - } else { // no overlap
 384+ } else { // no overlap, store current range and continue with next
314385
315386 $nextmin->modify( '-1 day' );
316387 $mergedRanges[] = array( $currmin, $nextmin );
@@ -333,55 +404,64 @@
334405 }
335406
336407 /**
337 - * expects a comma-separated list of dates or date ranges in the format
 408+ * Creates an array of arrays of dates from an array of strings
 409+ *
 410+ * expects an array of strings containing dates or date ranges in the format
338411 * "yyyy/mm/dd" or "yyyy/mm/dd-yyyy/mm/dd"
339412 *
340413 * returns an array of arrays, each of the latter consisting of two dates
341414 * representing the start and end date of the range
342415 *
343 - * @param string
 416+ * The result array will contain null values for unparseable date strings
 417+ *
 418+ * @param array $rangesAsStrings array of strings with dates and date ranges
344419 * @return array of arrays of DateTimes
345420 */
346 - static private function createRangesArray ( $rangesAsStrings ) {
347 - // transform array of strings into array of array of dates
348 - return array_map(
349 - self::createRange(),
350 - $rangesAsStrings
351 - );
 421+ static private function createRangesArray ( $rangesAsStrings ) {
352422
353 - }
354 -
355 - private static function createRange( $range ) {
356 - if ( strpos ( $range, '-' ) === FALSE ) { // single date
357 - $date = date_create( $range );
358 - return ( $date ) ? array( $date, clone $date ):null;
359 - } else { // date range
360 - $dates = array_map( "date_create", explode( '-', $range ) );
361 - return ( $dates[0] && $dates[1] ) ? $dates:null;
362 - }
363 - }
 423+ // transform array of strings into array of array of dates
 424+ // have to use create_function to be PHP pre5.3 compatible
 425+ return array_map( create_function( '$range', '
364426
 427+ if ( strpos ( $range, "-" ) === FALSE ) { // single date
 428+ $date = date_create( $range );
 429+ return ( $date ) ? array( $date, clone $date ):null;
 430+ } else { // date range
 431+ $dates = array_map( "date_create", explode( "-", $range ) );
 432+ return ( $dates[0] && $dates[1] ) ? $dates:null;
 433+ }
 434+
 435+ ' ), $rangesAsStrings );
 436+
 437+ }
 438+
365439 /**
366440 * Takes an array of date ranges and returns an array containing the gaps
367 - * between the ranges of the input array.
368441 *
369 - * @param array of arrays of DateTimes
 442+ * The very first and the very last date of the original string are lost in
 443+ * the process, of course, as they do not delimit a gap. This means, after
 444+ * repeated inversion the result would eventually be empty.
 445+ *
 446+ * @param array $ranges of arrays of DateTimes
370447 * @return array of arrays of DateTimes
371448 */
372449 static private function invertRangesArray( $ranges ) {
373450
 451+ // the result (initially empty)
374452 $invRanges = null;
 453+
 454+ // the minimum of the current gap (initially none)
375455 $min = null;
376456
377457 foreach ( $ranges as $range ) {
378458
379 - if ( $min ) {
 459+ if ( $min ) { // if min date of current gap is known store gap
380460 $min->modify( "+1day " );
381461 $range[0]->modify( "-1day " );
382462 $invRanges[] = array( $min, $range[0] );
383463 }
384464
385 - $min = $range[1];
 465+ $min = $range[1]; // store min date of next gap
386466
387467 }
388468
@@ -392,90 +472,89 @@
393473 /**
394474 * Definition of input type "datepicker".
395475 *
396 - * Returns an array containing two elements: the html text to be included
397 - * and an empty string (the js code is written directly without piping it
398 - * through SF)
 476+ * Returns an array containing three elements: the html code to be included
 477+ * in the page, an empty string (instead of JS initialization code, which is
 478+ * inserted into the page directly) and the name of a JS function to be
 479+ * called to initialize the input.
399480 *
400 - * @return array of two strings
 481+ * @param string $cur_value current value of this field (which is sometimes null)
 482+ * @param string $input_name HTML name that this input should have
 483+ * @param boolean $is_mandatory indicates whether this field is mandatory for the user
 484+ * @param boolean $is_disabled indicates whether this field is disabled (meaning, the user can't edit)
 485+ * @param array $other_args hash representing all the other properties defined for this input in the form definition
 486+ * @return array of three strings
401487 */
402488 static function jqDatePickerHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
403489
404 - global $wgOut, $wgLang, $wgAmericanDates;
405 - global $sfgFieldNum, $sfgScriptPath, $sfigSettings;
406 - global $sfgTabIndex; // used to represent the current tab index in the form
 490+ global $wgOut, $wgLang, $wgAmericanDates; // MW variables
 491+ global $sfgFieldNum, $sfgScriptPath, $sfgTabIndex; // SF variables
 492+ global $sfigSettings; // SFI variables
407493
408 -
409494 // call common setup for all jqdatepickers
410495 self::jqDatePickerSetup();
411496
 497+ // The datepicker is created in three steps:
412498 // first: set up HTML attributes
 499+ // second: set up JS attributes
 500+ // third: assemble HTML and JS code
413501
414 - // array of attributes to pass to the input field
415 - $attribs = array(
416 - "class" => "createboxInput",
417 - "value" => $cur_value,
418 - "type" => "text"
419 - );
420502
 503+ // first: set up HTML attributes
 504+ // nothing much to do here, self::textHTML will take care od the standard stuff
421505
422 - // set size attrib
423 - if ( array_key_exists( 'size', $other_args ) ) $attribs['size'] = $other_args['size'];
424 -
425 - // set maxlength attrib
426 - if ( array_key_exists( 'maxlength', $other_args ) ) $attribs['maxlength'] = $other_args['maxlength'];
427 -
428 -
429 - // modify class attribute for mandatory form fields
430 - if ( $is_mandatory ) $attribs["class"] .= ' mandatory';
431 -
432 - // add user class(es) to class attribute of input field and to all other datepicker components
 506+ // store user class(es) for use with buttons
433507 if ( array_key_exists( 'class', $other_args ) ) {
434 - $attribs["class"] .= ' ' . $other_args['class'];
435508 $userClasses = $other_args['class'];
436 - }
 509+ } else $userClasses = "";
437510
438 - // set readonly attrib
439 - if ( array_key_exists( 'disable input field', $other_args )
440 - || ( !array_key_exists( 'enable input field', $other_args ) && $sfigSettings->datePickerDisableInputField )
441 - || $is_disabled ) {
 511+ // should the input field be disabled?
 512+ $inputFieldDisabled =
 513+ array_key_exists( 'disable input field', $other_args )
 514+ || ( !array_key_exists( 'enable input field', $other_args ) && $sfigSettings->datePickerDisableInputField )
 515+ || $is_disabled ;
442516
443 - $attribs["readonly"] = "1";
444 -
445 - }
446 -
447517 // second: set up JS attributes, but only if we need them
448518 if ( !$is_disabled ) {
449519
450520 // find min date, max date and disabled dates
451521
452522 // set first date
453 - if ( array_key_exists( 'first date', $other_args ) ) $minDate = date_create( $other_args['first date'] );
454 - elseif ( $sfigSettings->datePickerFirstDate ) $minDate = date_create( $sfigSettings->datePickerFirstDate );
455 - else $minDate = null;
 523+ if ( array_key_exists( 'first date', $other_args ) ) {
 524+ $minDate = date_create( $other_args['first date'] );
 525+ } elseif ( $sfigSettings->datePickerFirstDate ) {
 526+ $minDate = date_create( $sfigSettings->datePickerFirstDate );
 527+ } else {
 528+ $minDate = null;
 529+ }
456530
457 -
458 -
459531 // set last date
460 - if ( array_key_exists( 'last date', $other_args ) ) $maxDate = date_create( $other_args['last date'] );
461 - elseif ( $sfigSettings->datePickerLastDate ) $maxDate = date_create( $sfigSettings->datePickerLastDate );
462 - else $maxDate = null;
 532+ if ( array_key_exists( 'last date', $other_args ) ) {
 533+ $maxDate = date_create( $other_args['last date'] );
 534+ } elseif ( $sfigSettings->datePickerLastDate ) {
 535+ $maxDate = date_create( $sfigSettings->datePickerLastDate );
 536+ } else {
 537+ $maxDate = null;
 538+ }
463539
464 - // $disabledDates = null;
465 -
466 - // find possible values and invert them to get disabled values
 540+ // find allowed values and invert them to get disabled values
467541 if ( array_key_exists( 'possible_values', $other_args ) && count( $other_args['possible_values'] ) ) {
468542
469543 $enabledDates = self::sortAndMergeRanges( self::createRangesArray( $other_args['possible_values'] ) );
470544
471545 // correct min/max date to the first/last allowed value
472 - if ( !$minDate || $minDate < $enabledDates[0][0] ) $minDate = $enabledDates[0][0];
473 - if ( !$maxDate || $maxDate > $enabledDates[count( $enabledDates ) - 1][1] ) $maxDate = $enabledDates[count( $enabledDates ) - 1][1];
 546+ if ( !$minDate || $minDate < $enabledDates[0][0] ) {
 547+ $minDate = $enabledDates[0][0];
 548+ }
474549
 550+ if ( !$maxDate || $maxDate > $enabledDates[count( $enabledDates ) - 1][1] ) {
 551+ $maxDate = $enabledDates[count( $enabledDates ) - 1][1];
 552+ }
 553+
475554 $disabledDates = self::invertRangesArray( $enabledDates );
476555
477556 } else $disabledDates = array();
478557
479 - // add user-defined disabled values
 558+ // add user-defined or default disabled values
480559 if ( array_key_exists( 'disable dates', $other_args ) ) {
481560
482561 $disabledDates =
@@ -490,8 +569,10 @@
491570
492571 }
493572
 573+ // if a minDate is set, discard all disabled dates below the min date
494574 if ( $minDate ) {
495 - // discard all disabled dates below the min date
 575+
 576+ // discard all ranges of disabled dates that are entirely below the min date
496577 while ( $minDate && count( $disabledDates ) && $disabledDates[0][1] < $minDate ) array_shift( $disabledDates );
497578
498579 // if min date is in first disabled date range, discard that range and adjust min date
@@ -502,8 +583,10 @@
503584 }
504585 }
505586
 587+ // if a maxDate is set, discard all disabled dates above the max date
506588 if ( $maxDate ) {
507 - // discard all disabled dates above the max date
 589+
 590+ // discard all ranges of disabled dates that are entirely above the max date
508591 while ( count( $disabledDates ) && $disabledDates[count( $disabledDates ) - 1][0] > $maxDate ) array_pop( $disabledDates );
509592
510593 // if max date is in last disabled date range, discard that range and adjust max date
@@ -526,8 +609,11 @@
527610
528611
529612 // find disabled week days and mark them in an array
530 - if ( array_key_exists( "disable days of week", $other_args ) ) $disabledDaysString = $other_args['disable days of week'];
531 - else $disabledDaysString = $sfigSettings->datePickerDisabledDaysOfWeek;
 613+ if ( array_key_exists( "disable days of week", $other_args ) ) {
 614+ $disabledDaysString = $other_args['disable days of week'];
 615+ } else {
 616+ $disabledDaysString = $sfigSettings->datePickerDisabledDaysOfWeek;
 617+ }
532618
533619 if ( $disabledDaysString != null ) {
534620
@@ -546,10 +632,12 @@
547633 }
548634
549635 // find highlighted week days and mark them in an array
550 - if ( array_key_exists( "highlight days of week", $other_args ) ) $highlightedDaysString = $other_args['highlight days of week'];
551 - else $highlightedDaysString = $sfigSettings->datePickerHighlightedDaysOfWeek;
 636+ if ( array_key_exists( "highlight days of week", $other_args ) ) {
 637+ $highlightedDaysString = $other_args['highlight days of week'];
 638+ } else {
 639+ $highlightedDaysString = $sfigSettings->datePickerHighlightedDaysOfWeek;
 640+ }
552641
553 -
554642 if ( $highlightedDaysString != null ) {
555643
556644 $highlightedDays = array( false, false, false, false, false, false, false );
@@ -561,6 +649,7 @@
562650 }
563651
564652 }
 653+
565654 } else {
566655 $highlightedDays = null;
567656 }
@@ -568,11 +657,10 @@
569658 // set datepicker widget attributes
570659 $jsattribs = array(
571660 'showOn' => 'both',
572 - 'buttonImage' => $sfigSettings->scriptPath . '/DatePickerButton.gif',
 661+ 'buttonImage' => $sfigSettings->scriptPath . '/images/DatePickerButton.gif',
573662 'buttonImageOnly' => false,
574663 'changeMonth' => true,
575664 'changeYear' => true,
576 - 'altField' => "#input_{$sfgFieldNum}",
577665 'altFormat' => "yy/mm/dd",
578666 // Today button does not work (http://dev.jqueryui.com/ticket/4045)
579667 // do not show button panel for now
@@ -581,9 +669,13 @@
582670 );
583671
584672 // set first day of the week
585 - if ( array_key_exists( 'week start', $other_args ) ) $jsattribs['firstDay'] = $other_args['week start'];
586 - else if ( $sfigSettings->datePickerWeekStart != null ) $jsattribs['firstDay'] = $sfigSettings->datePickerWeekStart;
587 - else $jsattribs['firstDay'] = wfMsg( 'semanticformsinputs-firstdayofweek' );
 673+ if ( array_key_exists( 'week start', $other_args ) ) {
 674+ $jsattribs['firstDay'] = $other_args['week start'];
 675+ } elseif ( $sfigSettings->datePickerWeekStart != null ) {
 676+ $jsattribs['firstDay'] = $sfigSettings->datePickerWeekStart;
 677+ } else {
 678+ $jsattribs['firstDay'] = wfMsg( 'semanticformsinputs-firstdayofweek' );
 679+ }
588680
589681 // set show week number
590682 if ( array_key_exists( 'show week numbers', $other_args )
@@ -594,19 +686,30 @@
595687 }
596688
597689 // set date format
 690+ // SHORT and LONG are SFI specific acronyms and are translated here
 691+ // into format strings, anything else is passed to the jQuery date picker
 692+ // Americans need special treatment
598693 if ( $wgAmericanDates && $wgLang->getCode() == "en" ) {
599694
600695 if ( array_key_exists( 'date format', $other_args ) ) {
601696
602 - if ( $other_args['date format'] == 'SHORT' ) $jsattribs['dateFormat'] = 'mm/dd/yy';
603 - elseif ( $other_args['date format'] == 'LONG' ) $jsattribs['dateFormat'] = 'MM d, yy';
604 - else $jsattribs['dateFormat'] = $other_args['date format'];
 697+ if ( $other_args['date format'] == 'SHORT' ) {
 698+ $jsattribs['dateFormat'] = 'mm/dd/yy';
 699+ } elseif ( $other_args['date format'] == 'LONG' ) {
 700+ $jsattribs['dateFormat'] = 'MM d, yy';
 701+ } else {
 702+ $jsattribs['dateFormat'] = $other_args['date format'];
 703+ }
605704
606705 } elseif ( $sfigSettings->datePickerDateFormat ) {
607706
608 - if ( $sfigSettings->datePickerDateFormat == 'SHORT' ) $jsattribs['dateFormat'] = 'mm/dd/yy';
609 - elseif ( $sfigSettings->datePickerDateFormat == 'LONG' ) $jsattribs['dateFormat'] = 'MM d, yy';
610 - else $jsattribs['dateFormat'] = $sfigSettings->datePickerDateFormat;
 707+ if ( $sfigSettings->datePickerDateFormat == 'SHORT' ) {
 708+ $jsattribs['dateFormat'] = 'mm/dd/yy';
 709+ } elseif ( $sfigSettings->datePickerDateFormat == 'LONG' ) {
 710+ $jsattribs['dateFormat'] = 'MM d, yy';
 711+ } else {
 712+ $jsattribs['dateFormat'] = $sfigSettings->datePickerDateFormat;
 713+ }
611714
612715 } else $jsattribs['dateFormat'] = 'yy/mm/dd';
613716
@@ -614,15 +717,23 @@
615718
616719 if ( array_key_exists( 'date format', $other_args ) ) {
617720
618 - if ( $other_args['date format'] == 'SHORT' ) $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatshort' );
619 - elseif ( $other_args['date format'] == 'LONG' ) $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatlong' );
620 - else $jsattribs['dateFormat'] = $other_args['date format'];
 721+ if ( $other_args['date format'] == 'SHORT' ) {
 722+ $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatshort' );
 723+ } elseif ( $other_args['date format'] == 'LONG' ) {
 724+ $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatlong' );
 725+ } else {
 726+ $jsattribs['dateFormat'] = $other_args['date format'];
 727+ }
621728
622729 } elseif ( $sfigSettings->datePickerDateFormat ) {
623730
624 - if ( $sfigSettings->datePickerDateFormat == 'SHORT' ) $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatshort' );
625 - elseif ( $sfigSettings->datePickerDateFormat == 'LONG' ) $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatlong' );
626 - else $jsattribs['dateFormat'] = $sfigSettings->datePickerDateFormat;
 731+ if ( $sfigSettings->datePickerDateFormat == 'SHORT' ) {
 732+ $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatshort' );
 733+ } elseif ( $sfigSettings->datePickerDateFormat == 'LONG' ) {
 734+ $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatlong' );
 735+ } else {
 736+ $jsattribs['dateFormat'] = $sfigSettings->datePickerDateFormat;
 737+ }
627738
628739 } else $jsattribs['dateFormat'] = 'yy/mm/dd';
629740
@@ -631,45 +742,49 @@
632743 }
633744
634745
635 - // third: build HTML and JS code
 746+ // third: assemble HTML and JS code
636747
637 -
638748 if ( $is_disabled ) {
639749
640 - $attribs[ 'id' ] = "input_{$sfgFieldNum}";
641 - $attribs[ 'name' ] = $input_name;
 750+ // if the input field is disabled, create a mockup without functionality
642751
643 - // no JS needed on a disabled datepicker, but we need to append the disabled button ourselves
644 - $html = Html::element( "input", $attribs )
645 - . Html::rawElement( "button",
 752+ // first create a simple text input and an inert button
 753+ $html = self::textHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args, null, null, "createboxInput" )
 754+
 755+ . Xml::element( "button",
646756 array(
647757 'type' => 'button',
648758 'class' => $userClasses,
649759 'disabled' => '1',
650760 'id' => "input_{$sfgFieldNum}_button"
651 - ),
652 - Html::element( "image",
653 - array( 'src' => $sfigSettings->scriptPath . '/DatePickerButtonDisabled.gif' )
 761+ ) )
654762
655 - )
656 - );
 763+ . Xml::element( "image",
 764+ array(
 765+ 'src' => $sfigSettings->scriptPath . '/images/DatePickerButtonDisabled.gif'
 766+ ) )
657767
 768+ . Xml::closeElement( "button" );
 769+
658770 // append reset button if required
659771 if ( array_key_exists( 'show reset button', $other_args ) ||
660772 $sfigSettings->datePickerShowResetButton && !array_key_exists( 'hide reset button', $other_args ) ) {
661773
662 - $html .= Html::rawElement( "button",
 774+ $html .= Xml::openElement( "button",
663775 array(
664776 'type' => 'button',
665777 'class' => $userClasses,
666778 'disabled' => '1',
667779 'id' => "input_{$sfgFieldNum}_resetbutton"
668 - ),
669 - Html::element( "image",
670 - array( 'src' => $sfigSettings->scriptPath . '/DatePickerResetButtonDisabled.gif' )
671 - )
672 - );
 780+ ) )
673781
 782+ . Xml::element( "image",
 783+ array(
 784+ 'src' => $sfigSettings->scriptPath . '/images/DatePickerResetButtonDisabled.gif'
 785+ ) )
 786+
 787+ . Xml::closeElement( "button" );
 788+
674789 }
675790
676791 // no JS needed on a disabled datepicker
@@ -677,70 +792,78 @@
678793
679794 } else {
680795
681 - $attribs[ 'id' ] = "input_{$sfgFieldNum}_show";
682 - $attribs[ 'tabindex' ] = $sfgTabIndex;
 796+ // start with the displayed input and append the real, but hidden
 797+ // input that gets sent to SF; it will be filled by the datepicker
 798+ $html = self::textHTML( $cur_value, "", $is_mandatory, $inputFieldDisabled,
 799+ $other_args, "input_{$sfgFieldNum}_show", null, "createboxInput" )
683800
684 - // start with the displayed input and
685 - // append the real, but hidden input that gets sent to SF;
686 - // it will be filled by the datepicker
687 - $html = Html::element( "input", $attribs )
688 - . Html::element( "input",
 801+ . Xml::element( "input",
689802 array(
690803 "id" => "input_{$sfgFieldNum}",
691804 "name" => $input_name,
692805 "type" => "hidden"
693 - )
694 - );
 806+ ) );
695807
696808 // append reset button if required
697809 if ( array_key_exists( 'show reset button', $other_args ) ||
698 - $sfigSettings->datePickerShowResetButton && !array_key_exists( 'hide reset button', $other_args ) ) {
 810+ ( !array_key_exists( 'hide reset button', $other_args ) && $sfigSettings->datePickerShowResetButton ) ) {
699811
 812+ // can not use Xml::element, it would sanitize the onclick attribute
700813 $html .= "<button "
701 - . Html::expandAttributes ( array(
 814+ . Xml::expandAttributes ( array(
702815 'type' => 'button',
703816 'class' => $userClasses,
704817 'id' => "input_{$sfgFieldNum}_resetbutton",
705818 ) )
706 - . "onclick= \"document.getElementById('input_{$sfgFieldNum}').value='';document.getElementById('input_{$sfgFieldNum}_show').value='';\""
 819+ . "onclick= \"\n"
 820+ . "document.getElementById(this.id.replace('_resetbutton','')).value='';"
 821+ . "document.getElementById(this.id.replace('_resetbutton','_show')).value='';"
 822+ . "\""
707823 . ">"
708 - . Html::element( "image", array( 'src' => $sfigSettings->scriptPath . '/DatePickerResetButton.gif' ) )
709 - . "</button>";
710824
 825+ . Xml::element( "image",
 826+ array(
 827+ 'src' => $sfigSettings->scriptPath . '/images/DatePickerResetButton.gif'
 828+ ) )
 829+
 830+ . Xml::closeElement( "button" );
 831+
711832 }
712833
 834+ // sanitize current value before putting it into the JS code
713835 $cur_value = Xml::escapeJsString( $cur_value );
714836
715 -
716 - // build JS array
 837+ // build JS code from attributes array
717838 $jsattribsString = Xml::encodeJsVar( $jsattribs );
718839
719 - // attach datepicker to input field
 840+ // assemble JS code to attach datepicker to input field
720841 $jstext = <<<JAVASCRIPT
721 - jQuery (
722 - function() {
723 - jQuery("#input_{$sfgFieldNum}_show").datepicker( $jsattribsString );
724 - jQuery("#input_{$sfgFieldNum}_show").datepicker( "setDate", jQuery.datepicker.parseDate("yy/mm/dd", "$cur_value", null) );
 842+ jQuery("#" + inputId + "_show").datepicker( $jsattribsString );
 843+ jQuery("#" + inputId + "_show").datepicker( "setDate", jQuery.datepicker.parseDate("yy/mm/dd", "$cur_value", null) );
 844+ jQuery("#" + inputId + "_show").datepicker( "option", "altField", "#" + inputId);
 845+ jQuery("#" + inputId + "_show").change(function() {
 846+ jQuery("#" + inputId ).attr("value", jQuery.datepicker.parseDate(jQuery(this).datepicker( "option", "dateFormat"), jQuery(this).attr("value"), null));
 847+ });
725848
726849 JAVASCRIPT;
727850
728 - // set first date
 851+ // append setting of first date
729852 if ( $minDate ) {
730853
731854 $minDateString = $minDate->format( 'Y-m-d' );
732855 $jstext .= <<<JAVASCRIPT
733 - jQuery("#input_{$sfgFieldNum}_show").datepicker( "option", "minDate", jQuery.datepicker.parseDate("yy/mm/dd", "$minDateString", null) );
 856+ jQuery("#" + inputId + "_show").datepicker( "option", "minDate", jQuery.datepicker.parseDate("yy/mm/dd", "$minDateString", null) );
734857
735858 JAVASCRIPT;
736859 }
737860
738 - // set last date
 861+ // append setting of last date
739862 if ( $maxDate ) {
740863
741864 $maxDateString = $maxDate->format( 'Y-m-d' );
742865
743866 $jstext .= <<<JAVASCRIPT
744 - jQuery("#input_{$sfgFieldNum}_show").datepicker( "option", "maxDate", jQuery.datepicker.parseDate("yy/mm/dd", "$maxDateString", null) );
 867+ jQuery("#" + inputId + "_show").datepicker( "option", "maxDate", jQuery.datepicker.parseDate("yy/mm/dd", "$maxDateString", null) );
745868
746869 JAVASCRIPT;
747870 }
@@ -749,85 +872,438 @@
750873 // add user-defined class(es) to all datepicker components
751874 if ( array_key_exists( 'class', $other_args ) ) {
752875
 876+ // sanitize names of user-defined classes
753877 $userClasses = Xml::encodeJsVar ( $userClasses );
754878
755879 $jstext .= <<<JAVASCRIPT
756 - jQuery("#input_{$sfgFieldNum}_show").datepicker("widget").addClass({$userClasses});
757 - jQuery("#input_{$sfgFieldNum}_show + button").addClass({$userClasses});
 880+ jQuery("#" + inputId + "_show").datepicker("widget").addClass({$userClasses});
 881+ jQuery("#" + inputId + "_show + button").addClass({$userClasses});
758882
759883 JAVASCRIPT;
760 -
761884 }
762885
763 - // register disabled dates
764 - // attach event handler to handle disabled dates
 886+ // attach event handler to handle disabled and highlighted dates
765887 if ( count( $disabledDates ) || count( $highlightedDates ) || count( $disabledDays ) || count( $highlightedDays ) ) {
766888
767 - // register disabled dates with datepicker
 889+ // first register disabled dates with datepicker
768890 if ( count( $disabledDates ) ) {
769891
770 - $disabledDatesString = '[' . implode( ',', array_map( self::createDateString(), $disabledDates ) ) . ']';
 892+ // convert the PHP array of date ranges into a JS array definition
 893+ $disabledDatesString = '[' . implode( ',', array_map( create_function ( '$range', '
771894
772 - $jstext .= " jQuery(\"#input_{$sfgFieldNum}_show\").datepicker(\"option\", \"disabledDates\", $disabledDatesString);\n";
 895+ $y0 = $range[0]->format( "Y" );
 896+ $m0 = $range[0]->format( "m" ) - 1;
 897+ $d0 = $range[0]->format( "d" );
773898
 899+ $y1 = $range[1]->format( "Y" );
 900+ $m1 = $range[1]->format( "m" ) - 1;
 901+ $d1 = $range[1]->format( "d" );
 902+
 903+ return "[new Date({$y0}, {$m0}, {$d0}), new Date({$y1}, {$m1}, {$d1})]";
 904+ ' ) , $disabledDates ) ) . ']';
 905+
 906+ // register array of disabled dates with datepicker
 907+ $jstext .= " jQuery(\"#\" + inputId + \"_show\").datepicker(\"option\", \"disabledDates\", $disabledDatesString);\n";
 908+
774909 }
775910
776 - // register highlighted dates with datepicker
777 - if ( count( $highlightedDates ) ) {
 911+ // then register highlighted dates with datepicker
 912+ if ( count( $highlightedDates ) > 0 ) {
778913
779 - $highlightedDatesString = '[' . implode( ',', array_map( self::createDateString(), $highlightedDates ) ) . ']';
 914+ // convert the PHP array of date ranges into a JS array definition
 915+ $highlightedDatesString = '[' . implode( ',', array_map( create_function ( '$range', '
780916
781 - $jstext .= " jQuery(\"#input_{$sfgFieldNum}_show\").datepicker(\"option\", \"highlightedDates\", $highlightedDatesString);\n";
 917+ $y0 = $range[0]->format( "Y" );
 918+ $m0 = $range[0]->format( "m" ) - 1;
 919+ $d0 = $range[0]->format( "d" );
782920
 921+ $y1 = $range[1]->format( "Y" );
 922+ $m1 = $range[1]->format( "m" ) - 1;
 923+ $d1 = $range[1]->format( "d" );
 924+
 925+ return "[new Date({$y0}, {$m0}, {$d0}), new Date({$y1}, {$m1}, {$d1})]";
 926+ ' ) , $highlightedDates ) ) . ']';
 927+
 928+ // register array of highlighted dates with datepicker
 929+ $jstext .= " jQuery(\"#\" + inputId + \"_show\").datepicker(\"option\", \"highlightedDates\", $highlightedDatesString);\n";
 930+
783931 }
784932
785933 // register disabled days of week with datepicker
786934 if ( count( $disabledDays ) ) {
787935 $disabledDaysString = Xml::encodeJsVar( $disabledDays );
788 - $jstext .= " jQuery(\"#input_{$sfgFieldNum}_show\").datepicker(\"option\", \"disabledDays\", $disabledDaysString);\n";
 936+ $jstext .= " jQuery(\"#\" + inputId + \"_show\").datepicker(\"option\", \"disabledDays\", $disabledDaysString);\n";
789937 }
790938
791939 // register highlighted days of week with datepicker
792940 if ( count( $highlightedDays ) ) {
793941 $highlightedDaysString = Xml::encodeJsVar( $highlightedDays );
794 - $jstext .= " jQuery(\"#input_{$sfgFieldNum}_show\").datepicker(\"option\", \"highlightedDays\", $highlightedDaysString);\n";
 942+ $jstext .= " jQuery(\"#\" + inputId + \"_show\").datepicker(\"option\", \"highlightedDays\", $highlightedDaysString);\n";
795943 }
796944
 945+ // attach the event handler to the datepicker's beforeShowDay event
 946+ // the actual handler function is loaded separately and uses the
 947+ // data atached to the datepicker above
797948 $jstext .= <<<JAVASCRIPT
798949
799 - jQuery("#input_{$sfgFieldNum}_show").datepicker("option", "beforeShowDay", function (date) {return SFI_DP_checkDate(this, date);});
 950+ jQuery("#" + inputId + "_show").datepicker("option", "beforeShowDay", function (date) {return SFI_DP_checkDate(this, date);});
800951
801952 JAVASCRIPT;
802953 }
803954
804 - // close JS code fragment
805 - $jstext .= <<<JAVASCRIPT
806 - }
807 - );
 955+ // wrap the JS code fragment in a function which can be called by SF for deferred init
 956+ $jstext = <<<JAVASCRIPT
 957+ function initInput$sfgFieldNum(inputId) {
 958+$jstext
 959+ }
808960
 961+ addOnloadHook(function(){initInput$sfgFieldNum("input_$sfgFieldNum");});
809962 JAVASCRIPT;
810963
811964
812965 }
813 -
 966+
814967 // add span for error messages (e.g. used for mandatory inputs)
815 - $html .= Html::element( "span", array( "id" => "info_$sfgFieldNum", "class" => "errorMessage" ) );
 968+ $html .= Xml::element( "span", array( "id" => "info_$sfgFieldNum", "class" => "errorMessage" ) );
816969
 970+ // directly insert the code of the JS init function into the pages code
 971+ // there seemed to be issues when this code was piped through SF
817972 $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' );
818973
819 - return array( $html, "" );
 974+ return array( $html, "", "initInput$sfgFieldNum" );
 975+
820976 }
821 -
822 - private static function createDateString( $range ) {
823 - $y0 = $range[0]->format( "Y" );
824 - $m0 = $range[0]->format( "m" ) - 1;
825 - $d0 = $range[0]->format( "d" );
 977+//
 978+// static function wysiwygSetup() {
 979+//
 980+// }
 981+//
 982+//
 983+// static function wysiwygHTML ( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
 984+//
 985+// global $wgOut, $wgLang, $wgAmericanDates, $wgScriptPath, $wgFCKEditorDir;
 986+// global $sfgFieldNum, $sfgScriptPath, $sfigSettings;
 987+// global $sfgTabIndex, $sfgJSValidationCalls; // used to represent the current tab index in the form
 988+//
 989+// $htmltext = Html::element('textarea', array(
 990+// 'id' => "input_$sfgFieldNum",
 991+// 'class' => 'createboxInput',
 992+// 'name' => $input_name,
 993+// 'tabindex' => $sfgTabIndex,
 994+// 'rows' => 25,
 995+// 'cols' => 80
 996+// ));
 997+//
 998+// $jstext = <<<JAVASCRIPT
 999+// addOnloadHook(function()
 1000+// {
 1001+// var oFCKeditor = new FCKeditor( 'input_$sfgFieldNum', '100%', '100%') ;
 1002+// oFCKeditor.BasePath = "$wgScriptPath/$wgFCKEditorDir/" ;
 1003+// oFCKeditor.ReplaceTextarea() ;
 1004+// });
 1005+//
 1006+// JAVASCRIPT;
 1007+//
 1008+// $sfgJSValidationCalls[] = "function() {document.getElementById('input_$sfgFieldNum').value = FCKeditorAPI.GetInstance('input_$sfgFieldNum').GetHtml();return true;}";
 1009+//
 1010+// $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' );
 1011+// return array( $htmltext, "" );
 1012+// }
 1013+//
8261014
827 - $y1 = $range[1]->format( "Y" );
828 - $m1 = $range[1]->format( "m" ) - 1;
829 - $d1 = $range[1]->format( "d" );
8301015
831 - return "[new Date({$y0}, {$m0}, {$d0}), new Date({$y1}, {$m1}, {$d1})]";
 1016+ /**
 1017+ * Setup for input type "timepicker".
 1018+ *
 1019+ * Adds the Javascript code and css used by all timepickers.
 1020+ */
 1021+ static private function timepickerSetup() {
 1022+
 1023+ global $sfigSettings, $wgOut;
 1024+
 1025+ static $hasRun = false;
 1026+
 1027+ if ( !$hasRun ) {
 1028+
 1029+ $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->scriptPath . '/libs/timepicker.js"></script> ' );
 1030+ $wgOut->addExtensionStyle( $sfigSettings->scriptPath . '/skins/SFI_Timepicker.css' );
 1031+
 1032+ }
 1033+
8321034 }
833 -
 1035+
 1036+ /**
 1037+ * Definition of input type "timepicker"
 1038+ *
 1039+ * Returns an array containing three elements: the html code to be included
 1040+ * in the page, an empty string (instead of JS initialization code, which is
 1041+ * inserted into the page directly) and the name of a JS function to be
 1042+ * called to initialize the input.
 1043+ *
 1044+ * @param string $cur_value current value of this field (which is sometimes null)
 1045+ * @param string $input_name HTML name that this input should have
 1046+ * @param boolean $is_mandatory indicates whether this field is mandatory for the user
 1047+ * @param boolean $is_disabled indicates whether this field is disabled (meaning, the user can't edit)
 1048+ * @param array $other_args hash representing all the other properties defined for this input in the form definition
 1049+ * @return array of three strings
 1050+ */
 1051+ static function timepickerHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
 1052+
 1053+ global $wgOut;
 1054+ global $sfgFieldNum;
 1055+ global $sfigSettings;
 1056+
 1057+ // The timepicker is created in four steps:
 1058+ // first: set up HTML attributes
 1059+ // second: assemble HTML
 1060+ // third: set up JS attributes
 1061+ // fourth: assemble JS call
 1062+
 1063+
 1064+ // first: set up HTML attributes
 1065+ $inputFieldDisabled =
 1066+ array_key_exists( 'disable input field', $other_args )
 1067+ || ( !array_key_exists( 'enable input field', $other_args ) && $sfigSettings->timePickerDisableInputField )
 1068+ || $is_disabled ;
 1069+
 1070+ if ( array_key_exists( 'class', $other_args ) ) $userClasses = $other_args['class'];
 1071+ else $userClasses = "";
 1072+
 1073+ // second: assemble HTML
 1074+ // create visible input field (for display) and invisible field (for data)
 1075+ $html = self::textHTML( $cur_value, '', $is_mandatory, $inputFieldDisabled, $other_args, "input_{$sfgFieldNum}_show", null, "createboxInput" )
 1076+ . Xml::element( "input", array(
 1077+ 'id' => "input_{$sfgFieldNum}",
 1078+ 'type' => 'hidden',
 1079+ 'name' => $input_name,
 1080+ 'value' => $cur_value
 1081+ ) );
 1082+
 1083+ // append time picker button
 1084+ if ( $is_disabled ) {
 1085+
 1086+ $html .= Xml::openElement(
 1087+ "button",
 1088+ array(
 1089+ 'type' => 'button',
 1090+ 'class' => 'createboxInput ' . $userClasses,
 1091+ 'disabled' => '1',
 1092+ 'id' => "input_{$sfgFieldNum}_button"
 1093+ ) )
 1094+
 1095+ . Xml::element(
 1096+ "image",
 1097+ array( 'src' => $sfigSettings->scriptPath . '/images/TimePickerButtonDisabled.gif' )
 1098+ )
 1099+
 1100+ . Xml::closeElement( "button" );
 1101+
 1102+ } else {
 1103+
 1104+ $html .= "<button "
 1105+ . Xml::expandAttributes ( array(
 1106+ 'type' => 'button',
 1107+ 'class' => 'createboxInput ' . $userClasses,
 1108+ 'id' => "input_{$sfgFieldNum}_button",
 1109+ ) )
 1110+ . "onclick=\"document.getElementById(this.id.replace('_button','_show')).focus();\""
 1111+ . ">"
 1112+
 1113+ . Xml::element(
 1114+ "image",
 1115+ array( 'src' => $sfigSettings->scriptPath . '/images/TimePickerButton.gif' )
 1116+ )
 1117+
 1118+ . Xml::closeElement( "button" );
 1119+
 1120+ }
 1121+
 1122+ // append reset button (if selected)
 1123+ if ( array_key_exists( 'show reset button', $other_args ) ||
 1124+ $sfigSettings->timePickerShowResetButton && !array_key_exists( 'hide reset button', $other_args ) ) {
 1125+
 1126+ if ( $is_disabled ) {
 1127+
 1128+ $html .= Xml::openElement(
 1129+ "button",
 1130+ array(
 1131+ 'type' => 'button',
 1132+ 'class' => 'createboxInput ' . $userClasses,
 1133+ 'disabled' => '1',
 1134+ 'id' => "input_{$sfgFieldNum}_resetbutton"
 1135+ ) )
 1136+
 1137+ . Xml::element(
 1138+ "image",
 1139+ array( 'src' => $sfigSettings->scriptPath . '/images/TimePickerResetButtonDisabled.gif' )
 1140+
 1141+ )
 1142+ . Xml::closeElement( "button" );
 1143+
 1144+ } else {
 1145+
 1146+ $html .= "<button "
 1147+ . Xml::expandAttributes ( array(
 1148+ 'type' => 'button',
 1149+ 'class' => 'createboxInput ' . $userClasses,
 1150+ 'id' => "input_{$sfgFieldNum}_resetbutton",
 1151+ ) )
 1152+ . "onclick=\"document.getElementById(this.id.replace('_resetbutton','')).value='';"
 1153+ . "document.getElementById(this.id.replace('_resetbutton','_show')).value='';\""
 1154+ . ">"
 1155+
 1156+ . Xml::element(
 1157+ "image",
 1158+ array( 'src' => $sfigSettings->scriptPath . '/images/TimePickerResetButton.gif' )
 1159+
 1160+ )
 1161+ . Xml::closeElement( "button" );
 1162+
 1163+ }
 1164+ }
 1165+
 1166+ // append span for error messages (e.g. fore mandatory fields)
 1167+ $html .= Xml::element( "span", array( "id" => "info_$sfgFieldNum", "class" => "errorMessage" ) );
 1168+
 1169+ // third: if the timepicker is not disabled set up JS attributes ans assemble JS call
 1170+ if ( !$is_disabled ) {
 1171+
 1172+ self::timepickerSetup();
 1173+
 1174+// if ( array_key_exists( 'delimiter', $other_args ) ) {
 1175+// $delimiter = $other_args[ 'delimiter' ];
 1176+// } else {
 1177+// $delimiter = ' ';
 1178+// }
 1179+//
 1180+ // set min time if valid, else use default
 1181+ if ( array_key_exists( 'mintime', $other_args )
 1182+ && ( preg_match( '/^\d+:\d\d$/', trim( $other_args['mintime'] ) ) == 1 ) ) {
 1183+ $minTime = trim( $other_args[ 'mintime' ] );
 1184+ } else {
 1185+ $minTime = '00:00';
 1186+ }
 1187+
 1188+ // set max time if valid, else use default
 1189+ if ( array_key_exists( 'maxtime', $other_args )
 1190+ && ( preg_match( '/^\d+:\d\d$/', trim( $other_args['maxtime'] ) ) == 1 ) ) {
 1191+ $maxTime = trim( $other_args[ 'maxtime' ] );
 1192+ } else {
 1193+ $maxTime = '23:59';
 1194+ }
 1195+
 1196+ // set interval if valid, else use default
 1197+ if ( array_key_exists( 'interval', $other_args )
 1198+ && preg_match( '/^\d+$/', trim( $other_args['interval'] ) ) == 1 ) {
 1199+ $interval = trim( $other_args[ 'interval' ] );
 1200+ } else {
 1201+ $interval = '15';
 1202+ }
 1203+
 1204+ $jstext = <<<JAVASCRIPT
 1205+ addOnloadHook(function(){SFI_TP_init ( "input_$sfgFieldNum", "$minTime", "$maxTime", "$interval", "" );});
 1206+JAVASCRIPT;
 1207+
 1208+ // write JS code directly to the page's code
 1209+ $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' );
 1210+
 1211+ // return HTML and name of JS init function
 1212+ //return array( $html, "", "initInput$sfgFieldNum" );
 1213+ return $html;
 1214+
 1215+ } else {
 1216+
 1217+ return $html;
 1218+
 1219+ }
 1220+
 1221+ }
 1222+
 1223+ /**
 1224+ * Setup for input type "menuselect".
 1225+ * Adds the Javascript code and css used by all menuselects.
 1226+ */
 1227+ static private function menuselectSetup() {
 1228+
 1229+ global $wgOut;
 1230+ global $sfigSettings;
 1231+
 1232+ static $hasRun = false;
 1233+
 1234+ if ( !$hasRun ) {
 1235+
 1236+ $wgOut->addScript( '<script type="text/javascript">sfigScriptPath="' . $sfigSettings->scriptPath . '";</script> ' );
 1237+ $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->scriptPath . '/libs/menuselect.js"></script> ' );
 1238+ $wgOut->addExtensionStyle( $sfigSettings->scriptPath . '/skins/SFI_Menuselect.css' );
 1239+
 1240+ }
 1241+
 1242+ }
 1243+
 1244+ /**
 1245+ * Definition of input type "menuselect"
 1246+ *
 1247+ * Returns an array containing two elements: the html text to be included
 1248+ * and an empty string (no JS code necessary)
 1249+ *
 1250+ * @return array of two strings
 1251+ */
 1252+ static function menuselectHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
 1253+ global $wgParser, $wgUser, $wgTitle, $wgOut;
 1254+ global $sfgFieldNum;
 1255+ global $sfigSettings;
 1256+
 1257+ self::menuselectSetup();
 1258+
 1259+ // first: set up HTML attributes
 1260+ $inputFieldDisabled =
 1261+ array_key_exists( 'disable input field', $other_args )
 1262+ || ( !array_key_exists( 'enable input field', $other_args ) && $sfigSettings->timePickerDisableInputField )
 1263+ || $is_disabled ;
 1264+
 1265+ // second: assemble HTML
 1266+ // create visible input field (for display) and invisible field (for data)
 1267+ $html = self::textHTML( $cur_value, '', $is_mandatory, $inputFieldDisabled, $other_args, "input_{$sfgFieldNum}_show", null, "createboxInput" )
 1268+ . Xml::element( "input", array(
 1269+ 'id' => "input_{$sfgFieldNum}",
 1270+ 'type' => 'hidden',
 1271+ 'name' => $input_name,
 1272+ 'value' => $cur_value
 1273+ ) );
 1274+
 1275+
 1276+ $html .= "<span class='SFI_menuselect' id='input_{$sfgFieldNum}_tree'>";
 1277+
 1278+
 1279+ //if ( array_key_exists( 'delimiter', $other_args ) ) $delimiter = $other_args[ 'delimiter' ];
 1280+ //else $delimiter = ' ';
 1281+
 1282+ // parse menu structure
 1283+
 1284+ $options = ParserOptions::newFromUser( $wgUser );
 1285+
 1286+ $oldStripState = $wgParser->mStripState;
 1287+ $wgParser->mStripState = new StripState();
 1288+
 1289+ //FIXME: SF does not parse options correctly. Users have to replace | by {{!}}
 1290+ $structure = str_replace('{{!}}','|',$other_args["structure"]);
 1291+
 1292+ $structure = $wgParser->parse($structure, $wgTitle, $options )->getText();
 1293+
 1294+ $wgParser->mStripState = $oldStripState;
 1295+
 1296+
 1297+ $html .= str_replace('<li', '<li class=\'ui-state-default\'', $structure);
 1298+
 1299+ $html .= "</span>";
 1300+
 1301+ $jstext = <<<JAVASCRIPT
 1302+ addOnloadHook(function(){SFI_MS_init("input_$sfgFieldNum");});
 1303+JAVASCRIPT;
 1304+
 1305+ // write JS code directly to the page's code
 1306+ $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' );
 1307+ return array( $html, "", "SFI_MS_init" );
 1308+
 1309+ }
8341310 }
Index: trunk/extensions/SemanticFormsInputs/libs/menuselect.js
@@ -0,0 +1,263 @@
 2+/**
 3+ * Javascript code to be used with input type menuselect.
 4+ *
 5+ * @author Stephan Gambke
 6+ * @version 0.4 alpha
 7+ *
 8+ */
 9+
 10+/**
 11+ * Initializes a menuselect input
 12+ *
 13+ * @param inputID ( String ) the id of the input to initialize
 14+ */
 15+function SFI_MS_init( inputID ) {
 16+
 17+ jQuery("#" + inputID + "_tree").css("visibility","hidden");
 18+
 19+ // wrap content in span to separate content from sub-menus,
 20+ // wrap content in div to support animating the list item width later
 21+ jQuery( "#" + inputID + "_tree li" ).each(
 22+ function() {
 23+
 24+ jQuery( this ).contents().not( "ul" )
 25+ .wrapAll( '<span />' )
 26+ .wrapAll( '<div class="cont"/>' );
 27+
 28+ jQuery( this ).contents().not( "ul" )
 29+ .find("div.cont")
 30+ .css('position','fixed');
 31+
 32+ // insert the arrows indicating submenus
 33+ if ( jQuery( this ).children( "ul" ).length > 0 ) {
 34+ jQuery( this ).children( "span" ).children( "div" )
 35+ .before( '<div class="arrow" ><img src="' + sfigScriptPath + '/images/MenuSelectArrow.gif" /></div>' )
 36+ }
 37+
 38+ } );
 39+
 40+ // ensure labels of list item have constant width regardless of width of list item
 41+ // prevents layout changes when list item width is changed
 42+ // set position static ( was set to fixed to calculate text width )
 43+ jQuery( "#" + inputID + "_tree li>span>div.cont" ).each( function() {
 44+ jQuery( this ).width( jQuery( this ).outerWidth(true) + jQuery( this ).siblings("div.arrow").outerWidth(true) + 5);
 45+ jQuery( this ).css( "position", "static" );
 46+ } );
 47+
 48+ // add class for default state and fix dimensions
 49+ jQuery( "#" + inputID + "_tree li" )
 50+ .addClass( "ui-state-default" )
 51+ .each(
 52+ function() {
 53+ jQuery(this).height(jQuery(this).height());
 54+ jQuery(this).width(jQuery(this).width());
 55+
 56+ // to be used for restoring width after mouse leves this item
 57+ jQuery(this).data("width", jQuery(this).width());
 58+ }
 59+ );
 60+
 61+ // initially hide everything
 62+ jQuery( "#" + inputID + "_tree ul" )
 63+ .css({"z-index":1})
 64+ .hide()
 65+ .fadeTo(0, 0 );
 66+
 67+ // some crap "browsers" need special treatment
 68+ if ( jQuery.browser.msie ) {
 69+ jQuery( "#" + inputID + "_tree ul" ).css({ "position":"relative" });
 70+ }
 71+
 72+ // sanitize links
 73+ jQuery( "#" + inputID + "_tree" ).find( "a" )
 74+ .each(
 75+ function() {
 76+
 77+ // find title of target page
 78+ if ( jQuery( this ).hasClass( 'new' ) ) { // for red links get it from the href
 79+
 80+ regexp = /.*title=([^&]*).*/;
 81+ res = regexp.exec( jQuery( this ).attr( 'href' ) );
 82+
 83+ title = unescape( res[1] );
 84+
 85+ jQuery( this ).data( 'title', title ); // save title in data
 86+
 87+ } else { // for normal links title is in the links title attribute
 88+ jQuery( this )
 89+ .data( 'title', jQuery( this ).attr( 'title' ) ); // save title in data
 90+ }
 91+
 92+ jQuery( this )
 93+ .removeAttr( 'title' ) // remove title to prevent tooltips on links
 94+ .bind( "click", function( event ) {
 95+ event.preventDefault();
 96+ } ) // prevent following links
 97+
 98+ }
 99+ );
 100+
 101+ // attach event handlers
 102+
 103+ // mouse entered list item
 104+ jQuery( "#" + inputID + "_tree li" )
 105+ .mouseenter( function( evt ) {
 106+
 107+ // switch classes to change display style
 108+ jQuery( evt.currentTarget )
 109+ .removeClass( "ui-state-default" )
 110+ .addClass( "ui-state-hover" );
 111+
 112+ // if we reentered (i.e. moved mouse from item to sub-item)
 113+ if (jQuery( evt.currentTarget ).data( "timeout" ) != null) {
 114+
 115+ // clear any timeout that may still run on the list item
 116+ // (i.e. do not fade out submenu)
 117+ clearTimeout( jQuery( evt.currentTarget ).data( "timeout" ) );
 118+ jQuery( evt.currentTarget ).data( "timeout", null );
 119+
 120+ // abort further actions (just leave the submenu open)
 121+ return;
 122+ }
 123+
 124+
 125+ // if list item has sub-items...
 126+ if ( jQuery( evt.currentTarget ).children( "ul" ).length > 0 ) {
 127+
 128+ // set timeout to show sub-items
 129+ jQuery( evt.currentTarget )
 130+ .data( "timeout", setTimeout(
 131+ function() {
 132+
 133+ // clear timeout data
 134+ jQuery( evt.currentTarget ).data( "timeout", null );
 135+
 136+ // some crap "browsers" need special treatment
 137+ if ( jQuery.browser.msie ) {
 138+ jQuery( evt.currentTarget ).children( "ul" )
 139+ .css( {
 140+ "top": -jQuery( evt.currentTarget ).outerHeight(),
 141+ "left": jQuery( evt.currentTarget ).outerWidth() + 10
 142+ } );
 143+ }
 144+
 145+ // fade in sub-menu
 146+ // can not use fadeIn, it sets display:block
 147+ jQuery( evt.currentTarget ).children( "ul" )
 148+ .css( {
 149+ "display":"inline",
 150+ "z-index":100
 151+ } )
 152+ .fadeTo( 400, 1 );
 153+
 154+ w = jQuery( evt.currentTarget ).width();
 155+
 156+ // animate list item width
 157+ jQuery( evt.currentTarget )
 158+ .animate( { "width": w + 10 }, 100 );
 159+
 160+ }, 400 )
 161+ );
 162+ }
 163+
 164+ } );
 165+
 166+ // mouse left list item
 167+ jQuery( "#" + inputID + "_tree li" )
 168+ .mouseleave( function( evt ) {
 169+
 170+ // switch classes to change display style
 171+ jQuery( evt.currentTarget )
 172+ .removeClass( "ui-state-hover" )
 173+ .addClass( "ui-state-default" )
 174+
 175+ // if we just moved in and out of the item (without really hovering)
 176+ if (jQuery( evt.currentTarget ).data( "timeout" ) != null) {
 177+
 178+ // clear any timeout that may still run on the list item
 179+ // (i.e. do not fade in submenu)
 180+ clearTimeout( jQuery( evt.currentTarget ).data( "timeout" ) );
 181+ jQuery( evt.currentTarget ).data( "timeout", null );
 182+
 183+ // abort further actions (no need to close)
 184+ return;
 185+ }
 186+
 187+ // if list item has sub-items...
 188+ if ( jQuery( evt.currentTarget ).children( "ul" ).length > 0 ) {
 189+
 190+ // hide sub-items after a short pause
 191+ jQuery( evt.currentTarget ).data( "timeout", setTimeout(
 192+ function() {
 193+
 194+ // clear timeout data
 195+ jQuery( evt.currentTarget ).data( "timeout", null );
 196+
 197+ // fade out sub-menu
 198+ // when finished set display:none and put list item back in
 199+ // line ( i.e. animate to original width )
 200+ jQuery( evt.currentTarget ).children( "ul" )
 201+ .css( "z-index", 1 )
 202+ .fadeTo( 400, 0,
 203+ function() {
 204+
 205+ jQuery( this ).css( "display", "none" );
 206+
 207+ // animate list item width
 208+ jQuery( this ).parent()
 209+ .animate( { "width": jQuery( this ).parent().data( "width" ) }, 100 );
 210+ }
 211+ );
 212+
 213+ }, 400 )
 214+ );
 215+ }
 216+
 217+ } );
 218+
 219+ // clicked list item
 220+ jQuery( "#" + inputID + "_tree li" )
 221+ .mousedown( function() {
 222+
 223+ // set visible value and leave input
 224+ jQuery( "#" + inputID + "_show" ).attr( "value", jQuery( this )
 225+ .children( "span" ).find( "div.cont" ).text() ).blur();
 226+
 227+ // set hidden value that gets sent back to the server
 228+ link = jQuery( this ).children( "span" ).find( "div.cont>a" );
 229+
 230+ // if content is link
 231+ if ( link.length == 1 ) {
 232+
 233+ // use title set by MW
 234+ jQuery( "#" + inputID ).attr( "value", link.data( "title" ) );
 235+
 236+ } else {
 237+
 238+ // just use text of list item
 239+ jQuery( "#" + inputID ).attr( "value", jQuery( this ).children( "span" ).find( "div.cont" ).text() );
 240+
 241+ }
 242+ return false;
 243+
 244+ } );
 245+
 246+ // show top menu when input gets focus
 247+ jQuery( "#" + inputID + "_show" )
 248+ .focus( function() {
 249+ jQuery( "#" + inputID + "_tree>ul" ).css( "display", "inline" ).fadeTo( 400, 1 );
 250+ } );
 251+
 252+ // hide all menus when input loses focus
 253+ jQuery( "#" + inputID + "_show" )
 254+ .blur( function() {
 255+
 256+ jQuery( "#" + inputID + "_tree ul" ).fadeTo( 400, 0,
 257+ function() {
 258+ jQuery( this ).css( "display", "none" );
 259+ } );
 260+ } );
 261+
 262+ jQuery("#" + inputID + "_tree").css("visibility","visible");
 263+
 264+}
\ No newline at end of file
Property changes on: trunk/extensions/SemanticFormsInputs/libs/menuselect.js
___________________________________________________________________
Added: svn:eol-style
1265 + native
Index: trunk/extensions/SemanticFormsInputs/libs/regexp.js
@@ -0,0 +1,56 @@
 2+/**
 3+ * Javascript code to be used with input type regexp.
 4+ *
 5+ * @author Stephan Gambke
 6+ * @version 0.4 alpha
 7+ *
 8+ */
 9+
 10+/**
 11+ * Validates inputs of type regexp.
 12+ *
 13+ * @param input_number (Number) the number of the input to check
 14+ * @param retext (String) the regular expression the input's value has to match
 15+ * @param inverse (Boolean) if the check result shall be inverted
 16+ * @param message (String) the message too be printed if the input's value does not match
 17+ * @param multiple (Boolean) if the input is inside a multiple-instance formular
 18+ * @return (Boolean) true, if the input's value matches the regular expression in
 19+ * retext, false otherwise; the value is inverted if inverse is true
 20+ */
 21+function validate_input_with_regexp( input_number, retext, inverse, message, multiple ){
 22+
 23+ var decoded = jQuery( "<div/>" ).html( retext ).text();
 24+ var re = new RegExp( decoded );
 25+
 26+ if ( multiple ) {
 27+ res = true;
 28+ for ( i = 1; i <= num_elements; i++ ) {
 29+ field = document.getElementById( 'input_' + i + "_" + input_number );
 30+ if ( field ) {
 31+ match = re.test( field.value );
 32+
 33+ if ( !( match && !inverse ) && !( !match && inverse ) ) {
 34+ infobox = document.getElementById( 'info_' + i + "_" + input_number );
 35+ infobox.innerHTML += " " + message;
 36+ res=false;
 37+ }
 38+ }
 39+ }
 40+ return res;
 41+ } else {
 42+ field = document.getElementById( 'input_' + input_number );
 43+
 44+ jQuery( '#input_' + input_number ).parent().children( '.sfiErrorMessage' ).remove();
 45+
 46+ match = re.test( field.value );
 47+
 48+ if ( ( match && !inverse ) || ( !match && inverse ) ) {
 49+ return true;
 50+ } else {
 51+ jQuery(field).after( '<span class="sfiErrorMessage"> ' + message + '</span>');
 52+ //infobox = document.getElementById( 'info_' + input_number );
 53+ //infobox.innerHTML += " " + message;
 54+ return false;
 55+ }
 56+ }
 57+}
Property changes on: trunk/extensions/SemanticFormsInputs/libs/regexp.js
___________________________________________________________________
Added: svn:eol-style
158 + native
Index: trunk/extensions/SemanticFormsInputs/libs/datepicker.js
@@ -0,0 +1,62 @@
 2+/**
 3+ * Javascript code to be used with input type datepicker.
 4+ *
 5+ * @author Stephan Gambke
 6+ * @version 0.4 alpha
 7+ *
 8+ */
 9+
 10+/**
 11+ * Checks a date if it is to be enabled or highlighted
 12+ *
 13+ * This function is a callback function given to the jQuery datepicker to be
 14+ * called for every date before it is displayed.
 15+ *
 16+ * @param input the input the datepicker works on
 17+ * @param date the date object that is to be displayed
 18+ * @return Array(Boolean enabled, Boolean highlighted, "") determining the style and behaviour
 19+ */
 20+function SFI_DP_checkDate( input, date ) {
 21+
 22+ enable = true
 23+
 24+ disabledDates = jQuery( input ).datepicker( "option", "disabledDates" );
 25+
 26+ if ( disabledDates ) {
 27+ for ( i = 0; i < disabledDates.length; ++i ) {
 28+ if ( (date >= disabledDates[i][0] ) && ( date <= disabledDates[i][1] ) ) {
 29+ enable = false;
 30+ break;
 31+ }
 32+ }
 33+ }
 34+
 35+ disabledDays = jQuery( input ).datepicker( "option", "disabledDays" );
 36+
 37+ if ( disabledDays ) {
 38+ enable = enable && !disabledDays[ date.getDay() ];
 39+ }
 40+
 41+ highlightedDates = jQuery( input ).datepicker( "option", "highlightedDates" );
 42+ highlight = "";
 43+
 44+ if ( highlightedDates ) {
 45+ for ( i = 0; i < highlightedDates.length; ++i ) {
 46+ if ( ( date >= highlightedDates[i][0] ) && ( date <= highlightedDates[i][1] ) ) {
 47+ highlight = "ui-state-highlight";
 48+ break;
 49+ }
 50+ }
 51+ }
 52+
 53+ highlightedDays = jQuery( input ).datepicker( "option", "highlightedDays" );
 54+
 55+ if ( highlightedDays ) {
 56+ if ( highlightedDays[ date.getDay() ] ) {
 57+ highlight = "ui-state-highlight";
 58+ }
 59+ }
 60+
 61+ return [ enable, highlight, "" ];
 62+}
 63+
Property changes on: trunk/extensions/SemanticFormsInputs/libs/datepicker.js
___________________________________________________________________
Added: svn:eol-style
164 + native
Index: trunk/extensions/SemanticFormsInputs/libs/timepicker.js
@@ -0,0 +1,154 @@
 2+/**
 3+ * Javascript code to be used with input type timepicker.
 4+ *
 5+ * @author Stephan Gambke
 6+ * @version 0.4 alpha
 7+ *
 8+ */
 9+
 10+/**
 11+ * Initializes a timepicker input
 12+ *
 13+ * @param inputID (String) the id of the input to initialize
 14+ * @param minTime (String) the minimum time to be shown (format hh:mm)
 15+ * @param maxTime (String) the maximum time to be shown (format hh:mm)
 16+ * @param interval (String) the interval between selectable times in minutes
 17+ * @param format (String) a format string (unused) (do we even need it?)
 18+ *
 19+ */
 20+function SFI_TP_init( inputID, minTime, maxTime, interval, format ) {
 21+
 22+ // sanitize inputs
 23+ re = /^\d+:\d\d$/;
 24+
 25+ if ( re.test( minTime ) ) {
 26+
 27+ min = minTime.split( ':', 2 );
 28+ minh = Number( min[0] );
 29+ minm = Number( min[1] );
 30+
 31+ if ( minm > 59 ) minm = 59;
 32+
 33+ } else {
 34+ minh = 0;
 35+ minm = 0;
 36+ }
 37+
 38+ if ( re.test( maxTime ) ) {
 39+
 40+ max = maxTime.split( ':', 2 );
 41+ maxh = Number( max[0] );
 42+ maxm = Number( max[1] );
 43+
 44+ if ( maxm > 59 ) maxm = 59;
 45+
 46+ } else {
 47+ maxh = 23;
 48+ maxm = 59;
 49+ }
 50+
 51+ interv = Number( interval );
 52+
 53+ if ( interv < 1 ) interv = 1;
 54+ else if ( interv > 60 ) interv = 60;
 55+
 56+ // build html structure
 57+ sp = jQuery( "<span class='SFI_timepicker' id='" + inputID + "_tree' ></span>" ).insertAfter( "#" + inputID );
 58+
 59+ ulh = jQuery( "<ul>" ).appendTo( sp );
 60+
 61+
 62+ for ( h = minh; h <= maxh; ++h ) {
 63+
 64+ lih = jQuery( "<li class='ui-state-default'>" + ( ( h < 10 ) ? "0" : "" ) + h + "</li>" ).appendTo( ulh );
 65+
 66+ //TODO: Replace value for "show" by formatted string
 67+ lih
 68+ .data( "value", ( ( h < 10 ) ? "0" : "" ) + h + ":00" )
 69+ .data( "show", ( ( h < 10 ) ?"0" : "" ) + h + ":00" );
 70+
 71+ ulm = jQuery( "<ul>" ).appendTo( lih );
 72+
 73+ for ( m = ( (h == minh) ? minm : 0 ) ; m <= ( (h == maxh) ? maxm : 59 ); m += interv ) {
 74+
 75+ lim = jQuery( "<li class='ui-state-default'>" + ( ( m < 10 ) ? "0" : "" ) + m + "</li>" ).appendTo( ulm );
 76+
 77+ //TODO: Replace value for "show" by formatted string
 78+ lim
 79+ .data( "value", ( ( h < 10 ) ? "0" : "" ) + h + ":" + ( ( m < 10 ) ? "0" : "") + m )
 80+ .data( "show", ( ( h < 10 ) ? "0" : "") + h + ":" + ( ( m < 10 ) ? "0" : "" ) + m );
 81+
 82+ }
 83+
 84+ }
 85+
 86+ // initially hide everything
 87+ jQuery("#" + inputID + "_tree ul")
 88+ .hide();
 89+
 90+ // attach event handlers
 91+ jQuery("#" + inputID + "_tree li") // hours
 92+ .mouseover(function(evt){
 93+
 94+ // clear any timeout that may still run on the last list item
 95+ clearTimeout(jQuery(evt.currentTarget).data("timeout"));
 96+
 97+ jQuery(evt.currentTarget)
 98+
 99+ // switch classes to change display style
 100+ .removeClass("ui-state-default")
 101+ .addClass("ui-state-hover")
 102+
 103+ // set timeout to show minutes for selected hour
 104+ .data("timeout", setTimeout(
 105+ function(){
 106+ //console.log("mouseover timer " + jQuery(evt.currentTarget).text());
 107+ jQuery(evt.currentTarget).children().fadeIn();
 108+ },400));
 109+
 110+ });
 111+
 112+ jQuery("#" + inputID + "_tree li") // hours
 113+ .mouseout(function(evt){
 114+
 115+ // clear any timeout that may still run on this jQuery list item
 116+ clearTimeout(jQuery(evt.currentTarget).data("timeout"));
 117+
 118+ jQuery(evt.currentTarget)
 119+
 120+ // switch classes to change display style
 121+ .removeClass("ui-state-hover")
 122+ .addClass("ui-state-default")
 123+
 124+ // hide minutes after a short pause
 125+ .data("timeout", setTimeout(
 126+ function(){
 127+ //console.log("mouseout timer " + jQuery(evt.currentTarget).text());
 128+ jQuery(evt.currentTarget).children().fadeOut();
 129+ },400));
 130+
 131+ });
 132+
 133+ jQuery("#" + inputID + "_tree li") // hours, minutes
 134+ .mousedown(function(){
 135+ // set values and leave input
 136+ jQuery("#" + inputID + "_show").attr("value", jQuery(this).data("show")).blur();
 137+ jQuery("#" + inputID ).attr("value", jQuery(this).data("value"));
 138+ return false;
 139+ });
 140+
 141+ // show timepicker when input gets focus
 142+ jQuery("#" + inputID + "_show").focus(function() {
 143+ jQuery("#" + inputID + "_tree>ul").fadeIn();
 144+ });
 145+
 146+ // hide timepicker when input loses focus
 147+ jQuery("#" + inputID + "_show").blur(function() {
 148+ jQuery("#" + inputID + "_tree ul").fadeOut();
 149+ });
 150+
 151+ jQuery("#" + inputID + "_show").change(function() {
 152+ jQuery("#" + inputID ).attr("value", jQuery(this).attr("value"));
 153+ });
 154+
 155+}
\ No newline at end of file
Property changes on: trunk/extensions/SemanticFormsInputs/libs/timepicker.js
___________________________________________________________________
Added: svn:eol-style
1156 + native
Index: trunk/extensions/SemanticFormsInputs/README
@@ -16,15 +16,10 @@
1717
1818 == Installation ==
1919
20 -Having Semantic MediaWiki and Semantic Forms installed is a
21 -precondition for the Semantic Forms Inputs extension; the code
22 -will not work without it. The version of Semantic Forms must be at
23 -least 2.0 for the 'simpledatepicker' input to work.
 20+Having at least MediaWiki 1.16, Semantic MediaWiki 1.5.4 and Semantic
 21+Forms 2.07 installed is a precondition for the Semantic Forms Inputs
 22+extension; the code will not work without it.
2423
25 -For the 'datepicker' input to work the Yahoo! User Interface (YUI)
26 -Javascript library (version 2.7.0b or higher) must be available,
27 -either locally or via an existing internet connection.
28 -
2924 To install Semantic Forms Inputs, create a directory named
3025 SemanticFormsInputs in the extensions directory of your MediaWiki
3126 installation and copy the extension's files into it. Then add the

Follow-up revisions

RevisionCommit summaryAuthorDate
r79277followup r79270 (some more file structuring)foxtrott17:53, 30 December 2010
r79278followup r79270 (some more file structuring)foxtrott17:53, 30 December 2010
r79279Merging from r79149 through r79270 of headawjrichards17:54, 30 December 2010
r79288followup r79270 (include missing style sheet)...foxtrott19:55, 30 December 2010

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r75634Added support for the semantic extension type and incremented version numberjeroendedauw23:45, 28 October 2010
r78976Attempt to fix bug 25917jeroendedauw19:51, 24 December 2010

Comments

#Comment by Jeroen De Dauw (talk | contribs)   17:36, 30 December 2010

Oops, looks like I hit the wrong key in the r75634 version number change :)

Status & tagging log