r72443 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r72442‎ | r72443 | r72444 >
Date:15:06, 5 September 2010
Author:foxtrott
Status:deferred
Tags:
Comment:
Replaced YUI datepicker by jQuery datepicker

Also fixed bug 25017
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.i18n.php (modified) (history)
  • /trunk/extensions/SemanticFormsInputs/SemanticFormsInputs.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticFormsInputs/SemanticFormsInputs.i18n.php
@@ -7,7 +7,14 @@
88
99 $messages['en'] = array(
1010 'semanticformsinputs-desc' => 'Additional input types for [http://www.mediawiki.org/wiki/Extension:Semantic_Forms Semantic Forms]',
11 - 'semanticformsinputs-wrongformat' => 'Wrong format.'
 11+ 'semanticformsinputs-wrongformat' => 'Wrong format.',
 12+ 'semanticformsinputs-close' => 'Close',
 13+ 'semanticformsinputs-prev' => 'Previous',
 14+ 'semanticformsinputs-next' => 'Next',
 15+ 'semanticformsinputs-today' => 'Today',
 16+ 'semanticformsinputs-dateformatlong' => 'd MM yy', // see http://docs.jquery.com/UI/Datepicker/formatDate
 17+ 'semanticformsinputs-dateformatshort' => 'dd/mm/yy', // see http://docs.jquery.com/UI/Datepicker/formatDate
 18+ 'semanticformsinputs-firstdayofweek' => '0' // 0 - sunday, 1 - monday...
1219 );
1320
1421 /** Message documentation (Message documentation)
@@ -56,6 +63,13 @@
5764 $messages['de'] = array(
5865 'semanticformsinputs-desc' => 'Ermöglicht zusätzliche Eingabearten für [http://www.mediawiki.org/wiki/Extension:Semantic_Forms Semantic Forms]',
5966 'semanticformsinputs-wrongformat' => 'Falsches Format.',
 67+ 'semanticformsinputs-close' => 'Schließen',
 68+ 'semanticformsinputs-prev' => 'Voriger Monat',
 69+ 'semanticformsinputs-next' => 'Nächster Monat',
 70+ 'semanticformsinputs-today' => 'Heute',
 71+ 'semanticformsinputs-dateformatlong' => 'd. MM yy', // see http://docs.jquery.com/UI/Datepicker/formatDate
 72+ 'semanticformsinputs-dateformatshort' => 'dd.mm.yy', // see http://docs.jquery.com/UI/Datepicker/formatDate
 73+ 'semanticformsinputs-firstdayofweek' => '1' // 0 - sunday, 1 - monday...
6074 );
6175
6276 /** French (Français) */
Index: trunk/extensions/SemanticFormsInputs/SemanticFormsInputs.php
@@ -25,7 +25,7 @@
2626 'author' => array( '[http://www.mediawiki.org/wiki/User:F.trott Stephan Gambke]', 'Sanyam Goyal', 'Yaron Koren' ),
2727 'url' => 'http://www.mediawiki.org/wiki/Extension:Semantic_Forms_Inputs',
2828 'descriptionmsg' => 'semanticformsinputs-desc',
29 - 'version' => '0.3',
 29+ 'version' => '0.3.1',
3030 );
3131
3232 // load user settings
@@ -67,7 +67,7 @@
6868 global $sfgFormPrinter, $wgOut;
6969
7070 $sfgFormPrinter->setInputTypeHook( 'regexp', array( 'SFIInputs', 'regexpHTML' ), array() );
71 - $sfgFormPrinter->setInputTypeHook( 'datepicker', array( 'SFIInputs', 'datePickerHTML' ), array() );
 71+ $sfgFormPrinter->setInputTypeHook( 'datepicker', array( 'SFIInputs', 'jqDatePickerHTML' ), array() );
7272 $sfgFormPrinter->setInputTypeHook( 'simpledatepicker', array( 'SFIInputs', 'jqDatePickerHTML' ), array() );
7373
7474 $wgOut->addInlineScript( 'sfiElements = new Object();' );
Index: trunk/extensions/SemanticFormsInputs/SFI_Settings.php
@@ -3,161 +3,131 @@
44 * Settings for the Semantic Forms Inputs extension.
55 *
66 * @author Stephan Gambke
7 - * @version 0.3
8 - * @date 06-Nov-2009
 7+ * @version 0.3.1
98 *
109 * To change the default settings you can uncomment (or copy) the
1110 * examples here and adjust them to your needs. You may as well
1211 * include them in your LocalSettings.php.
1312 */
1413
15 -###
 14+# # #
1615 # This is the path to your installation of Semantic Forms Inputs as
1716 # seen from the web. No final slash.
18 -##
 17+# #
1918 $sfigSettings->scriptPath = $wgScriptPath . '/extensions/SemanticFormsInputs';
2019
21 -###
22 -# This is the base URL for the YUI (Yahoo! User Interface) files
23 -# used by the 'datepicker' input, and possibly other input types
24 -# in the futre.
25 -##
26 -$sfigSettings->yuiBase = "http://yui.yahooapis.com/2.7.0/build/";
 20+# # # Date Picker Settings
2721
28 -### Date Picker Settings
29 -
30 -###
31 -# This is the first selectable date (format dd/mm/yyyy)
32 -# Sample value: '01/01/2005'
33 -##
 22+# # #
 23+# This is the first selectable date (format yyyy/mm/dd)
 24+# Sample value: '2005/01/01'
 25+# #
3426 $sfigSettings->datePickerFirstDate = null;
3527
36 -###
37 -# This is the last selectable date (format dd/mm/yyyy)
38 -# Sample value: '31/12/2015'
39 -##
 28+# # #
 29+# This is the last selectable date (format yyyy/mm/dd)
 30+# Sample value: '2015/31/12'
 31+# #
4032 $sfigSettings->datePickerLastDate = null;
4133
42 -###
43 -# The date format string. It is used for the input and for the date sent back with the form. Use the following keys:
 34+# # #
 35+# The date format string used for the user input.
 36+# The date sent back to the form is fixed to yyyy/mm/dd
 37+# (that is, yy/mm/dd in the format code below).
4438 #
45 -# %a - abbreviated weekday name according to the current locale
46 -# %A - full weekday name according to the current locale
47 -# %b - abbreviated month name according to the current locale
48 -# %B - full month name according to the current locale
49 -# %c - preferred date and time representation for the en locale
50 -# %C - century number (the year divided by 100 and truncated to an integer, range 00 to 99)
51 -# %d - day of the month as a decimal number (range 01 to 31)
52 -# %D - same as %m/%d/%y
53 -# %e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31')
54 -# %F - same as %Y-%m-%d (ISO 8601 date format)
55 -# %g - like %G, but without the century
56 -# %G - The 4-digit year corresponding to the ISO week number
57 -# %h - same as %b
58 -# %H - hour as a decimal number using a 24-hour clock (range 00 to 23)
59 -# %I - hour as a decimal number using a 12-hour clock (range 01 to 12)
60 -# %j - day of the year as a decimal number (range 001 to 366)
61 -# %k - hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
62 -# %l - hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
63 -# %m - month as a decimal number (range 01 to 12)
64 -# %M - minute as a decimal number
65 -# %n - newline character
66 -# %p - either `AM' or `PM' according to the given time value
67 -# %P - like %p, but lower case
68 -# %r - time in a.m. and p.m. notation equal to %I:%M:%S %p
69 -# %R - time in 24 hour notation equal to %H:%M
70 -# %s - number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
71 -# %S - second as a decimal number
72 -# %t - tab character
73 -# %T - current time, equal to %H:%M:%S
74 -# %u - weekday as a decimal number [1,7], with 1 representing Monday
75 -# %U - week number of the current year as a decimal number, starting with the first Sunday as the first day of the first week
76 -# %V - The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53,
77 -# where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week.
78 -# %w - day of the week as a decimal, Sunday being 0
79 -# %W - week number of the current year as a decimal number, starting with the first Monday as the first day of the first week
80 -# %x - preferred date representation for the en locale without the time
81 -# %X - preferred time representation for the en locale without the date
82 -# %y - year as a decimal number without a century (range 00 to 99)
83 -# %Y - year as a decimal number including the century
84 -# %z - numerical time zone representation
85 -# %Z - time zone name or abbreviation
86 -# %% - a literal `%' character
87 -##
88 -if ( $wgAmericanDates )
89 - $sfigSettings->datePickerDateFormat = '%m/%d/%Y';
90 -else
91 - $sfigSettings->datePickerDateFormat = '%d/%m/%Y';
 39+# The format can be combinations of the following:
 40+#
 41+# d - day of month (no leading zero)
 42+# dd - day of month (two digit)
 43+# o - day of the year (no leading zeros)
 44+# oo - day of the year (three digit)
 45+# D - day name short
 46+# DD - day name long
 47+# m - month of year (no leading zero)
 48+# mm - month of year (two digit)
 49+# M - month name short
 50+# MM - month name long
 51+# y - year (two digit)
 52+# yy - year (four digit)
 53+# @ - Unix timestamp (ms since 01/01/1970)
 54+# ! - Windows ticks (100ns since 01/01/0001)
 55+# '...' - literal text
 56+# '' - single quote
 57+# anything else - literal text
 58+#
 59+# There are also a number of predefined standard date formats available:
 60+#
 61+# SHORT - short date format localized to the wiki user language
 62+# LONG - long date format localized to the wiki user language
 63+# ATOM - 'yy-mm-dd' (Same as RFC 3339/ISO 8601)
 64+# COOKIE - 'D, dd M yy'
 65+# ISO_8601 - 'yy-mm-dd'
 66+# RFC_822 - 'D, d M y' (See RFC 822)
 67+# RFC_850 - 'DD, dd-M-y' (See RFC 850)
 68+# RFC_1036 - 'D, d M y' (See RFC 1036)
 69+# RFC_1123 - 'D, d M yy' (See RFC 1123)
 70+# RFC_2822 - 'D, d M yy' (See RFC 2822)
 71+# RSS - 'D, d M y' (Same as RFC 822)
 72+# TICKS - '!'
 73+# TIMESTAMP - '@'
 74+# W3C - 'yy-mm-dd' (Same as ISO 8601)
 75+# #
 76+$sfigSettings->datePickerDateFormat = 'SHORT';
9277
93 -###
94 -# This determines the start of the week in the display
 78+# # #
 79+# This determines the start of the week in the display.
9580 # Set it to: 0 (Zero) for Sunday, 1 (One) for Monday etc.
 81+# If set to null the day is localized to the wiki user language
9682 # Sample value: 1
97 -##
98 -$sfigSettings->datePickerWeekStart = 0;
 83+# #
 84+$sfigSettings->datePickerWeekStart = null;
9985
100 -###
 86+# # #
10187 # This determines if the number of the week shall be shown.
102 -##
 88+# #
10389 $sfigSettings->datePickerShowWeekNumbers = false;
10490
105 -###
 91+# # #
10692 # This determines if the input field shall be disabled. The user can
10793 # only set the date via the datepicker in this case.
108 -##
 94+# #
10995 $sfigSettings->datePickerDisableInputField = false;
11096
111 -###
 97+# # #
11298 # This determines if a reset button shall be shown. This is the only
11399 # way to erase the input field if it is disabled for direct input.
114 -##
 100+# #
115101 $sfigSettings->datePickerShowResetButton = false;
116102
117 -###
 103+# # #
118104 # This is a string of disabled days of the week, i.e. days the user can not
119105 # pick. The days must be given as comma-separated list of numbers starting
120106 # with 0 for Sunday.
121107 # Sample value: "6,0"
122 -##
123 -$sfigSettings->datePickerDisabledDaysOfWeek = "";
 108+# #
 109+$sfigSettings->datePickerDisabledDaysOfWeek = null;
124110
125 -###
 111+# # #
126112 # This is a string of highlighted days of the week. The days must be given as
127113 # comma-separated list of numbers starting with 0 for Sunday.
128114 # Sample value: "6,0"
129 -##
130 -$sfigSettings->datePickerHighlightedDaysOfWeek = "";
 115+# #
 116+$sfigSettings->datePickerHighlightedDaysOfWeek = null;
131117
132 -###
 118+# # #
133119 # This is a string of disabled dates, i.e. days the user cannot pick. The
134120 # days must be given as comma-separated list of dates or date ranges. The
135 -# format for days is DD/MM/YYYY, for date ranges use DD/MM/YYYY-DD/MM/YYYY.
 121+# format for days is yyyy/mm/dd, for date ranges use yyyy/mm/dd-yyyy/mm/dd.
136122 # Spaces are permissible.
137 -# Sample value: "25/12/2009 - 06/01/2010, 01/05/2010"
138 -##
139 -$sfigSettings->datePickerDisabledDates = "";
 123+# Sample value: "2010/12/25 - 2011/01/06, 2011/05/01"
 124+# #
 125+$sfigSettings->datePickerDisabledDates = null;
140126
141 -###
 127+# # #
142128 # This is a string of highlighted dates. The days must be given as
143129 # comma-separated list of dates or date ranges. The format for days is
144 -# DD/MM/YYYY, for date ranges use DD/MM/YYYY-DD/MM/YYYY. Spaces are
 130+# yyyy/mm/dd, for date ranges use yyyy/mm/dd-yyyy/mm/dd. Spaces are
145131 # permissible.
146 -# Sample value: "25/12/2009 - 06/01/2010, 01/05/2010"
147 -##
148 -$sfigSettings->datePickerHighlightedDates = "";
149 -
150 -###
151 -# This determines if long or short month names are shown. The month
152 -# names are the wiki month names according to the current locale.
153 -##
154 -$sfigSettings->datePickerMonthNames = "long";
155 -
156 -###
157 -# This determines the format of the names of the days of the
158 -# week. Possible values are 'long', 'medium', 'short', '1char'. The long
159 -# names are the wiki month names according to the current locale. Medium
160 -# names are the wiki short names, short names are the first 2
161 -# characters of the wiki short names and 1char are the initials of the
162 -# wiki short names.
163 -##
164 -$sfigSettings->datePickerDayNames = "short";
 132+# Sample value: "2010/12/25 - 2011/01/06, 2011/05/01"
 133+# #
 134+$sfigSettings->datePickerHighlightedDates = null;
Index: trunk/extensions/SemanticFormsInputs/SFI_Inputs.php
@@ -14,789 +14,831 @@
1515 }
1616
1717 class SFIInputs {
18 -/*
19 - * Setup for input type regexp.
20 - * Adds the Javascript code used by all regexp filters.
21 - */
22 -static function regexpSetup() {
2318
24 - global $wgOut;
 19+ /**
 20+ * Setup for input type regexp.
 21+ * Adds the Javascript code used by all regexp filters.
 22+ */
 23+ static private function regexpSetup() {
2524
26 - static $hasRun = false;
 25+ global $wgOut;
2726
28 - if ( !$hasRun ) {
29 - $hasRun = true;
 27+ static $hasRun = false;
3028
31 - wfLoadExtensionMessages( 'SemanticFormsInputs' );
 29+ if ( !$hasRun ) {
 30+ $hasRun = true;
3231
33 - $jstext = <<<JAVASCRIPT
34 - function validate_input_with_regexp(input_number, retext, inverse, message, multiple){
 32+ wfLoadExtensionMessages( 'SemanticFormsInputs' );
3533
36 - var decoded = jQuery("<div/>").html(retext).text();
37 - var re = new RegExp(decoded);
 34+ $jstext = <<<JAVASCRIPT
 35+ function validate_input_with_regexp(input_number, retext, inverse, message, multiple){
3836
39 - if (multiple) {
40 - res = true;
41 - for (i = 1; i <= num_elements; i++) {
42 - field = document.getElementById('input_' + i + "_" + input_number);
43 - if (field) {
44 - match = re.test(field.value);
 37+ var decoded = jQuery("<div/>").html(retext).text();
 38+ var re = new RegExp(decoded);
4539
46 - if ( !(match && !inverse) && !(!match && inverse) ) {
47 - infobox = document.getElementById('info_' + i + "_" + input_number);
48 - infobox.innerHTML += " " + message;
49 - res=false;
 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+ }
5052 }
5153 }
52 - }
53 - return res;
54 - } else {
55 - field = document.getElementById('input_' + input_number);
56 - match = re.test(field.value);
 54+ return res;
 55+ } else {
 56+ field = document.getElementById('input_' + input_number);
 57+ match = re.test(field.value);
5758
58 - if ( (match && !inverse) || (!match && inverse) ) {
59 - return true;
60 - } else {
61 - infobox = document.getElementById('info_' + input_number);
62 - infobox.innerHTML += " " + message;
63 - return false;
 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+ }
6466 }
6567 }
66 - }
6768 JAVASCRIPT;
6869
69 - $wgOut->addInlineScript( $jstext );
 70+ $wgOut->addInlineScript( $jstext );
 71+ }
7072 }
71 -}
7273
7374
74 -/*
75 - * Definition of input type "regexp"
76 - */
77 -static function regexpHTML ( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
 75+ /**
 76+ * Definition of input type "regexp"
 77+ *
 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)
 81+ *
 82+ * @return array of two strings
 83+ */
 84+ static function regexpHTML ( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
7885
79 - global $wgRequest, $wgUser, $wgParser;
80 - global $sfgTabIndex; // used to represent the current tab index in the form
81 - global $sfgFieldNum; // used for setting various HTML IDs
82 - global $sfgJSValidationCalls; // array of Javascript calls to determine if page can be saved
83 - global $sfgFormPrinter;
 86+ global $wgRequest, $wgUser, $wgParser;
 87+ global $sfgTabIndex; // used to represent the current tab index in the form
 88+ global $sfgFieldNum; // used for setting various HTML IDs
 89+ global $sfgJSValidationCalls; // array of Javascript calls to determine if page can be saved
 90+ global $sfgFormPrinter;
8491
85 - self::regexpSetup();
 92+ self::regexpSetup();
8693
87 - // set base type string
88 - if ( array_key_exists( 'base type', $other_args ) ) {
89 - $baseType = trim( $other_args['base type'] );
90 - unset( $other_args['base type'] );
91 - }
92 - else $baseType = null;
 94+ // set base type string
 95+ if ( array_key_exists( 'base type', $other_args ) ) {
 96+ $baseType = trim( $other_args['base type'] );
 97+ unset( $other_args['base type'] );
 98+ }
 99+ else $baseType = null;
93100
94 - if ( ! $baseType || ! array_key_exists( $baseType, $sfgFormPrinter->mInputTypeHooks ) )
95 - $baseType = 'text';
 101+ if ( ! $baseType || ! array_key_exists( $baseType, $sfgFormPrinter->mInputTypeHooks ) )
 102+ $baseType = 'text';
96103
97 - // set base prefix string
98 - if ( array_key_exists( 'base prefix', $other_args ) ) {
99 - $basePrefix = trim( $other_args['base prefix'] ) . ".";
100 - unset( $other_args['base prefix'] );
101 - }
102 - else $basePrefix = '';
 104+ // set base prefix string
 105+ if ( array_key_exists( 'base prefix', $other_args ) ) {
 106+ $basePrefix = trim( $other_args['base prefix'] ) . ".";
 107+ unset( $other_args['base prefix'] );
 108+ }
 109+ else $basePrefix = '';
103110
104 - // set OR character
105 - if ( array_key_exists( 'or char', $other_args ) ) {
106 - $orChar = trim( $other_args['or char'] );
107 - unset( $other_args['or char'] );
108 - }
109 - else $orChar = '!';
 111+ // set OR character
 112+ if ( array_key_exists( 'or char', $other_args ) ) {
 113+ $orChar = trim( $other_args['or char'] );
 114+ unset( $other_args['or char'] );
 115+ }
 116+ else $orChar = '!';
110117
111 - // set inverse string
112 - if ( array_key_exists( 'inverse', $other_args ) ) {
113 - $inverseString = 'true';
114 - unset( $other_args['inverse'] );
115 - }
116 - else $inverseString = 'false';
 118+ // set inverse string
 119+ if ( array_key_exists( 'inverse', $other_args ) ) {
 120+ $inverseString = 'true';
 121+ unset( $other_args['inverse'] );
 122+ }
 123+ else $inverseString = 'false';
117124
118 - // set regexp string
119 - if ( array_key_exists( 'regexp', $other_args ) ) {
 125+ // set regexp string
 126+ if ( array_key_exists( 'regexp', $other_args ) ) {
120127
121 - $regexp = str_replace( $orChar, '|', trim( $other_args['regexp'] ) );
122 - unset( $other_args['regexp'] );
 128+ $regexp = str_replace( $orChar, '|', trim( $other_args['regexp'] ) );
 129+ unset( $other_args['regexp'] );
123130
124 - // check for leading/trailing delimiter and remove it (else dump regexp)
125 - if ( preg_match ( "/^\/.*\/\$/", $regexp ) ) {
 131+ // check for leading/trailing delimiter and remove it (else dump regexp)
 132+ if ( preg_match ( "/^\/.*\/\$/", $regexp ) ) {
126133
127 - $regexp = substr( $regexp, 1, strlen( $regexp ) - 2 );
 134+ $regexp = substr( $regexp, 1, strlen( $regexp ) - 2 );
128135
 136+ }
 137+ else $regexp = '.*';
 138+
129139 }
130140 else $regexp = '.*';
131141
132 - }
133 - else $regexp = '.*';
 142+ // set failure message string
 143+ if ( array_key_exists( 'message', $other_args ) ) {
 144+ $message = trim( $other_args['message'] );
 145+ unset( $other_args['message'] );
 146+ }
 147+ else $message = wfMsg( 'semanticformsinputs-wrongformat' );
134148
135 - // set failure message string
136 - if ( array_key_exists( 'message', $other_args ) ) {
137 - $message = trim( $other_args['message'] );
138 - unset( $other_args['message'] );
139 - }
140 - else $message = wfMsg( 'semanticformsinputs-wrongformat' );
 149+ $new_other_args = array();
141150
142 - $new_other_args = array();
 151+ foreach ( $other_args as $key => $value )
 152+ if ( $basePrefix && strpos( $key, $basePrefix ) === 0 ) {
 153+ $new_other_args[substr( $key, strlen( $basePrefix ) )] = $value;
 154+ } else
 155+ $new_other_args[$key] = $value;
143156
144 - foreach ( $other_args as $key => $value )
145 - if ( $basePrefix && strpos( $key, $basePrefix ) === 0 ) {
146 - $new_other_args[substr( $key, strlen( $basePrefix ) )] = $value;
147 - } else
148 - $new_other_args[$key] = $value;
 157+ $funcArgs = array();
 158+ $funcArgs[] = $cur_value;
 159+ $funcArgs[] = $input_name;
 160+ $funcArgs[] = $is_mandatory;
 161+ $funcArgs[] = $is_disabled;
 162+ $funcArgs[] = $new_other_args;
149163
150 - $funcArgs = array();
151 - $funcArgs[] = $cur_value;
152 - $funcArgs[] = $input_name;
153 - $funcArgs[] = $is_mandatory;
154 - $funcArgs[] = $is_disabled;
155 - $funcArgs[] = $new_other_args;
 164+ $hook_values = $sfgFormPrinter->mInputTypeHooks[$baseType];
156165
157 - $hook_values = $sfgFormPrinter->mInputTypeHooks[$baseType];
 166+ // sanitize error message and regexp for JS
 167+ $message = Xml::encodeJsVar( $message );
 168+ $regexp = Xml::encodeJsVar( $regexp );
158169
159 - // sanitize error message and regexp for JS
160 - $message = Xml::encodeJsVar( $message );
161 - $regexp = Xml::encodeJsVar( $regexp );
 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+ }
162176
163 - // $sfgJSValidationCalls are sanitized for HTML by SF before output, no htmlspecialchars() here
164 - if ( array_key_exists( 'part_of_multiple', $other_args ) && $other_args['part_of_multiple'] == 1 ) {
165 - $sfgJSValidationCalls[] = "validate_input_with_regexp($sfgFieldNum, {$regexp}, {$inverseString}, {$message}, true)";
166 - } else {
167 - $sfgJSValidationCalls[] = "validate_input_with_regexp($sfgFieldNum, {$regexp}, {$inverseString}, {$message}, false)";
168 - }
 177+ list( $htmltext, $jstext ) = call_user_func_array( $hook_values[0], $funcArgs );
169178
170 - list( $htmltext, $jstext ) = call_user_func_array( $hook_values[0], $funcArgs );
 179+ $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' );
171180
172 - return array( $htmltext, $jstext );
173 -}
 181+ return array( $htmltext, "" );
174182
 183+ }
175184
176 -/*
177 - * Setup for input type datepicker.
178 - * Adds the Javascript code used by all date pickers.
179 - */
180 -static function datePickerSetup () {
181 - global $wgOut;
182 - global $sfigSettings;
183185
184 - static $hasRun = false;
 186+ /**
 187+ * Setup for input type jqdatepicker.
 188+ * Adds the Javascript code used by all date pickers.
 189+ */
 190+ static private function jqDatePickerSetup () {
 191+ global $wgOut, $wgLang, $sfgScriptPath;
 192+ global $sfigSettings;
185193
186 - if ( !$hasRun ) {
187 - $hasRun = true;
 194+ static $hasRun = false;
188195
189 - $wgOut->addLink( array(
190 - 'rel' => 'stylesheet',
191 - 'type' => 'text/css',
192 - 'media' => "screen",
193 - 'href' => $sfigSettings->yuiBase . "calendar/assets/skins/sam/calendar.css"
194 - ) );
195 - $wgOut->addLink( array(
196 - 'rel' => 'stylesheet',
197 - 'type' => 'text/css',
198 - 'media' => "screen",
199 - 'href' => $sfigSettings->yuiBase . "calendar/assets/skins/sam/calendar-skin.css"
200 - ) );
 196+ if ( !$hasRun ) {
 197+ $hasRun = true;
201198
202 - $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->yuiBase . 'yahoo-dom-event/yahoo-dom-event.js"></script> ' );
203 - $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->yuiBase . 'calendar/calendar-min.js"></script> ' );
204 - $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->yuiBase . 'datasource/datasource-min.js"></script> ' );
 199+ $wgOut->addScript( '<script type="text/javascript" src="' . $sfgScriptPath . '/libs/jquery-ui/jquery.ui.datepicker.min.js"></script> ' );
 200+ $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->scriptPath . '/libs/datepicker.js"></script> ' );
205201
206 - $locString = "function datePickerSetLocale() {\n" .
207 - 'YAHOO.util.DateLocale["wiki"] = YAHOO.lang.merge(YAHOO.util.DateLocale, {' . "\n" .
208 - 'a: ["' . wfMsg( 'sun' ) . '", "' .
209 - wfMsg( 'mon' ) . '", "' . wfMsg( 'tue' ) . '", "' . wfMsg( 'wed' ) . '", "' .
210 - wfMsg( 'thu' ) . '", "' . wfMsg( 'fri' ) . '", "' . wfMsg( 'sat' ) . '"],' . "\n" .
211 - 'A: ["' . wfMsg( 'sunday' ) . ' ", "' .
212 - wfMsg( 'monday' ) . '", "' . wfMsg( 'tuesday' ) . '", "' . wfMsg( 'wednesday' ) . '", "' .
213 - wfMsg( 'thursday' ) . '", "' . wfMsg( 'friday' ) . '", "' . wfMsg( 'saturday' ) . '"],' . "\n" .
214 - 'b: ["' .
215 - wfMsg( 'jan' ) . '", "' . wfMsg( 'feb' ) . '", "' . wfMsg( 'mar' ) . '", "' . wfMsg( 'apr' ) . '", "' .
216 - wfMsg( 'may' ) . '", "' . wfMsg( 'jun' ) . '", "' . wfMsg( 'jul' ) . '", "' . wfMsg( 'aug' ) . '", "' .
217 - wfMsg( 'sep' ) . '", "' . wfMsg( 'oct' ) . '", "' . wfMsg( 'nov' ) . '", "' . wfMsg( 'dec' ) . '"],' . "\n" .
218 - 'B: ["' .
219 - wfMsg( 'january' ) . '", "' . wfMsg( 'february' ) . '", "' . wfMsg( 'march' ) . '", "' .
220 - wfMsg( 'april' ) . '", "' . wfMsg( 'may-long' ) . '", "' . wfMsg( 'june' ) . '", "' .
221 - wfMsg( 'july' ) . '", "' . wfMsg( 'august' ) . '", "' . wfMsg( 'september' ) . '", "' .
222 - wfMsg( 'october' ) . '", "' . wfMsg( 'november' ) . '", "' . wfMsg( 'december' ) . '"]' . "\n" .
 202+ $jstext =
 203+ "jQuery(function($){\n"
 204+ . " $.datepicker.regional['wiki'] = {\n"
 205+ . " closeText: '" . wfMsg( 'semanticformsinputs-close' ) . "',\n"
 206+ . " prevText: '" . wfMsg( 'semanticformsinputs-prev' ) . "',\n"
 207+ . " nextText: '" . wfMsg( 'semanticformsinputs-next' ) . "',\n"
 208+ . " currentText: '" . wfMsg( 'semanticformsinputs-today' ) . "',\n"
 209+ . " monthNames: ['"
 210+ . wfMsg( 'january' ) . "','"
 211+ . wfMsg( 'february' ) . "','"
 212+ . wfMsg( 'march' ) . "','"
 213+ . wfMsg( 'april' ) . "','"
 214+ . wfMsg( 'may_long' ) . "','"
 215+ . wfMsg( 'june' ) . "','"
 216+ . wfMsg( 'july' ) . "','"
 217+ . wfMsg( 'august' ) . "','"
 218+ . wfMsg( 'september' ) . "','"
 219+ . wfMsg( 'october' ) . "','"
 220+ . wfMsg( 'november' ) . "','"
 221+ . wfMsg( 'december' ) . "'],\n"
 222+ . " monthNamesShort: ['"
 223+ . wfMsg( 'jan' ) . "','"
 224+ . wfMsg( 'feb' ) . "','"
 225+ . wfMsg( 'mar' ) . "','"
 226+ . wfMsg( 'apr' ) . "','"
 227+ . wfMsg( 'may' ) . "','"
 228+ . wfMsg( 'jun' ) . "','"
 229+ . wfMsg( 'jul' ) . "','"
 230+ . wfMsg( 'aug' ) . "','"
 231+ . wfMsg( 'sep' ) . "','"
 232+ . wfMsg( 'oct' ) . "','"
 233+ . wfMsg( 'nov' ) . "','"
 234+ . wfMsg( 'dec' ) . "'],\n"
 235+ . " dayNames: ['"
 236+ . wfMsg( 'sunday' ) . "','"
 237+ . wfMsg( 'monday' ) . "','"
 238+ . wfMsg( 'tuesday' ) . "','"
 239+ . wfMsg( 'wednesday' ) . "','"
 240+ . wfMsg( 'thursday' ) . "','"
 241+ . wfMsg( 'friday' ) . "','"
 242+ . wfMsg( 'saturday' ) . "'],\n"
 243+ . " dayNamesShort: ['"
 244+ . wfMsg( 'sun' ) . "','"
 245+ . wfMsg( 'mon' ) . "','"
 246+ . wfMsg( 'tue' ) . "','"
 247+ . wfMsg( 'wed' ) . "','"
 248+ . wfMsg( 'thu' ) . "','"
 249+ . wfMsg( 'fri' ) . "','"
 250+ . wfMsg( 'sat' ) . "'],\n"
 251+ . " dayNamesMin: ['"
 252+ . $wgLang->firstChar( wfMsg( 'sun' ) ) . "','"
 253+ . $wgLang->firstChar( wfMsg( 'mon' ) ) . "','"
 254+ . $wgLang->firstChar( wfMsg( 'tue' ) ) . "','"
 255+ . $wgLang->firstChar( wfMsg( 'wed' ) ) . "','"
 256+ . $wgLang->firstChar( wfMsg( 'thu' ) ) . "','"
 257+ . $wgLang->firstChar( wfMsg( 'fri' ) ) . "','"
 258+ . $wgLang->firstChar( wfMsg( 'sat' ) ) . "'],\n"
 259+ . " weekHeader: '',\n"
 260+ . " dateFormat: '" . wfMsg( 'semanticformsinputs-dateformat' ) . "',\n"
 261+ . " firstDay: '" . wfMsg( 'semanticformsinputs-firstday' ) . "',\n"
 262+ . " isRTL: " . ( $wgLang->isRTL() ? "true":"false" ) . ",\n"
 263+ . " showMonthAfterYear: false,\n"
 264+ . " yearSuffix: ''};\n"
 265+ . " $.datepicker.setDefaults($.datepicker.regional['wiki']);\n"
 266+ . "});\n";
223267
224 - "});\n" .
225268
226 - 'sfiElements["locale"] = new Object;' . "\n" .
 269+ $wgOut->addInlineScript( $jstext );
227270
228 - 'sfiElements["locale"].month_long = YAHOO.util.DateLocale["wiki"].B' . "\n" .
229 - 'sfiElements["locale"].month_short = YAHOO.util.DateLocale["wiki"].b' . "\n" .
230 - 'sfiElements["locale"].week_long = YAHOO.util.DateLocale["wiki"].A' . "\n" .
231 - 'sfiElements["locale"].week_medium = YAHOO.util.DateLocale["wiki"].a' . "\n" .
232 - 'sfiElements["locale"].week_short = new Array(YAHOO.util.DateLocale["wiki"].a.length);' . "\n" .
233 - 'sfiElements["locale"].week_1char = new Array(YAHOO.util.DateLocale["wiki"].a.length);' . "\n" .
234 - 'for (i=0; i < YAHOO.util.DateLocale["wiki"].a.length;++i) {' . "\n" .
235 - ' sfiElements["locale"].week_short[i] = YAHOO.util.DateLocale["wiki"].a[i].substr(0,2);' . "\n" .
236 - ' sfiElements["locale"].week_1char[i] = YAHOO.util.DateLocale["wiki"].a[i].substr(0,1);' . "\n" .
 271+ }
 272+ }
237273
238 - "}\n" .
239 - "}\n" .
240 - "addOnloadHook(datePickerSetLocale);";
 274+ /**
 275+ * expects a two dimensional array
 276+ * the inner arrays must contain two dates representing the start and end
 277+ * date of a time range
 278+ *
 279+ * returns an array with the same structur with the date ranges sorted and
 280+ * overlapping ranges merged
 281+ *
 282+ *
 283+ * @param array of arrays of DateTimes
 284+ * @return array of arrays of DateTimes
 285+ */
 286+ static private function sortAndMergeRanges ( $ranges ) {
241287
242 - $jstext = <<<JAVASCRIPT
243 - function toggle_datepicker(toggle_button) {
 288+ // sort ranges, earliest date first
 289+ sort( $ranges );
244290
245 - var id = toggle_button.id.replace("_button","");
 291+ $currmin = FALSE;
 292+ $nextmin = FALSE;
246293
247 - if (sfiElements[id]) {
248 - if (document.getElementById(id + "_calendar").style.display=="none")
249 - sfiElements[id].show();
250 - else sfiElements[id].hide();
251 - } else { //setup datepicker first
252 - var settings = id.replace(/input(_[0-9]+)?(_[0-9]+)/, "settings$2");
253 - //alert(settings);
 294+ $mergedRanges = array();
254295
255 - sfiElements[id] = new YAHOO.widget.Calendar(
256 - id + "_table",
257 - id + "_calendar",
258 - {
259 - navigator:true,
260 - START_WEEKDAY:sfiElements[settings].start_weekday,
261 - SHOW_WEEK_HEADER:sfiElements[settings].show_week_header,
262 - mindate:sfiElements[settings].first_day,
263 - maxdate:sfiElements[settings].last_day,
264 - LOCALE_MONTHS:sfiElements[settings].locale_months,
265 - LOCALE_WEEKDAYS:sfiElements[settings].locale_weekdays,
266 - MONTHS_LONG:sfiElements["locale"].month_long,
267 - MONTHS_SHORT:sfiElements["locale"].month_short,
268 - WEEKDAYS_LONG:sfiElements["locale"].week_long,
269 - WEEKDAYS_MEDIUM:sfiElements["locale"].week_medium,
270 - WEEKDAYS_SHORT:sfiElements["locale"].week_short,
271 - WEEKDAYS_1CHAR:sfiElements["locale"].week_1char
272 - });
 296+ foreach ( $ranges as $range ) {
273297
274 - for (i = 0; i < sfiElements[settings].disabled_days_of_week.length; ++i)
275 - sfiElements[id].addWeekdayRenderer(
276 - sfiElements[settings].disabled_days_of_week[i] + 1,
277 - sfiElements[id].renderOutOfBoundsDate
278 - );
 298+ if ( !$range ) continue;
279299
280 - for (i = 0; i < sfiElements[settings].highlighted_days_of_week.length; ++i)
281 - sfiElements[id].addWeekdayRenderer(
282 - sfiElements[settings].highlighted_days_of_week[i] + 1,
283 - sfiElements[id].renderCellStyleHighlight1
284 - );
 300+ if ( !$currmin ) { // found first valid range
285301
286 - for (i = 0; i < sfiElements[settings].disabled_days.length; ++i)
287 - sfiElements[id].addRenderer(
288 - sfiElements[settings].disabled_days[i],
289 - sfiElements[id].renderOutOfBoundsDate
290 - );
 302+ $currmin = $range[0];
 303+ $nextmin = $range[1];
 304+ $nextmin->modify( '+1 day' );
291305
292 - for (i = 0; i < sfiElements[settings].highlighted_days.length; ++i)
293 - sfiElements[id].addRenderer(
294 - sfiElements[settings].highlighted_days[i],
295 - sfiElements[id].renderCellStyleHighlight2
296 - );
 306+ } elseif ( $range[0] <= $nextmin ) { // overlap detected
297307
298 - //if (sfiElements[settings].default_day) sfiElements[id].select(sfiElements[settings].default_day);
 308+ $currmin = min( $currmin, $range[0] );
299309
300 - sfiElements[id].selectEvent.subscribe(
301 - function(type,arr,obj){
302 - var id = this.id.replace("_table","");
303 - var settings = id.replace(/input(_[0-9]+)?(_[0-9]+)/, "settings$2");
304 - document.getElementById(id).value=
305 - YAHOO.util.Date.format(
306 - this.toDate(arr[0][0]),
307 - {format:sfiElements[settings].date_format},
308 - 'wiki'
309 - );
310 - this.hide();
311 - },
312 - sfiElements[id],
313 - true
314 - );
 310+ $range[1]->modify( '+1 day' );
 311+ $nextmin = max( $nextmin, $range[1] );
315312
 313+ } else { // no overlap
316314
317 - //YAHOO.util.DOM.setXY(YAHOO.util.Dom.getX(id),YAHOO.util.Dom.getX(id));
 315+ $nextmin->modify( '-1 day' );
 316+ $mergedRanges[] = array( $currmin, $nextmin );
318317
319 - YAHOO.util.Event.addListener(document.getElementsByTagName("body")[0], "click", function(e, id){
320 - if (YAHOO.util.Event.getTarget(e).id != id + "_button")
321 - sfiElements[id].hide();
322 - }, id, false);
 318+ $currmin = $range[0];
 319+ $nextmin = $range[1];
 320+ $nextmin->modify( '+1 day' );
323321
324 - YAHOO.util.Event.addListener(id + "_container", "click", function(e){YAHOO.util.Event.stopEvent(e);});
 322+ }
325323
326 - //sfiElements[id].select(sfiElements[settings].default_day);
327 - sfiElements[id].render();
328 - sfiElements[id].show();
 324+ }
329325
 326+ // store last range
 327+ if ( $currmin ) {
 328+ $nextmin->modify( '-1 day' );
 329+ $mergedRanges[] = array( $currmin, $nextmin );
330330 }
331331
332 - return false;
333 - }
 332+ return $mergedRanges;
334333
335 - function reset_datepicker(toggle_button) {
336 - var id = toggle_button.id.replace("_resetbutton","");
337 - if (sfiElements[id]) sfiElements[id].clear();
338 - document.getElementById(id).value="";
339334 }
340335
341 -JAVASCRIPT;
 336+ /**
 337+ * expects a comma-separated list of dates or date ranges in the format
 338+ * "yyyy/mm/dd" or "yyyy/mm/dd-yyyy/mm/dd"
 339+ *
 340+ * returns an array of arrays, each of the latter consisting of two dates
 341+ * representing the start and end date of the range
 342+ *
 343+ * @param string
 344+ * @return array of arrays of DateTimes
 345+ */
 346+ static private function createRangesArray ( $rangesAsStrings ) {
342347
343 - $jstext .= $locString;
 348+ // transform array of strings into array of array of dates
 349+ return array_map(
 350+ function( $range ) {
344351
345 - $wgOut->addInlineScript( $jstext );
 352+ if ( strpos ( $range, '-' ) === FALSE ) { // single date
 353+ $date = date_create( $range );
 354+ return ( $date ) ? array( $date, clone $date ):null;
 355+ } else { // date range
 356+ $dates = array_map( "date_create", explode( '-', $range ) );
 357+ return ( $dates[0] && $dates[1] ) ? $dates:null;
 358+ }
 359+
 360+ } ,
 361+ $rangesAsStrings
 362+ );
 363+
346364 }
347 -}
348365
349 -/*
350 - * Definition of input type "simpledatepicker".
351 - */
352 -static function jqDatePickerHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
 366+ /**
 367+ * Takes an array of date ranges and returns an array containing the gaps
 368+ * between the ranges of the input array.
 369+ *
 370+ * @param array of arrays of DateTimes
 371+ * @return array of arrays of DateTimes
 372+ */
 373+ static private function invertRangesArray( $ranges ) {
353374
354 - global $wgRequest, $wgUser, $wgParser, $wgOut, $wgScriptPath, $wgLanguageCode;
355 - global $sfgFieldNum, $sfgScriptPath, $sfigSettings;
 375+ $invRanges = null;
 376+ $min = null;
356377
357 - static $hasRun = false;
 378+ foreach ( $ranges as $range ) {
358379
359 - if ( !$hasRun ) {
360 - $hasRun = true;
 380+ if ( $min ) {
 381+ $min->modify( "+1day " );
 382+ $range[0]->modify( "-1day " );
 383+ $invRanges[] = array( $min, $range[0] );
 384+ }
361385
362 - $wgOut->addScript( '<script type="text/javascript" src="' . $sfgScriptPath . '/libs/jquery-ui/jquery.ui.datepicker.min.js"></script> ' );
 386+ $min = $range[1];
363387
364 - if ( strcmp( $wgLanguageCode, "en" ) != 0 ) {
365 - $wgOut->addScript( '<script type="text/javascript" src="' . $sfgScriptPath . '/libs/jquery-ui/jquery-ui-i18n.js"></script> ' );
366388 }
367389
 390+ return $invRanges;
368391 }
369392
370 - if ( strcmp( $wgLanguageCode, "en" ) != 0 ) {
371 - $langCodeString = ", jQuery.datepicker.regional['$wgLanguageCode']";
372 - } else {
373 - $langCodeString = "";
374 - }
375393
376 - $jstext = <<<JAVASCRIPT
377 -jQuery (
378 - function() {
379 - jQuery("#input_$sfgFieldNum").datepicker({showOn: 'both', buttonImage: '$sfigSettings->scriptPath/DatePickerButton.gif', buttonImageOnly: false , dateFormat: 'yy-mm-dd' }$langCodeString);
380 - }
381 -);
 394+ /**
 395+ * Definition of input type "datepicker".
 396+ *
 397+ * Returns an array containing two elements: the html text to be included
 398+ * and an empty string (the js code is written directly without piping it
 399+ * through SF)
 400+ *
 401+ * @return array of two strings
 402+ */
 403+ static function jqDatePickerHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
382404
383 -JAVASCRIPT;
 405+ global $wgOut, $wgLang, $wgAmericanDates;
 406+ global $sfgFieldNum, $sfgScriptPath, $sfigSettings;
 407+ global $sfgTabIndex; // used to represent the current tab index in the form
384408
385 - $html = '<input type="text" id="input_' . $sfgFieldNum . '" name="' . htmlspecialchars( $input_name ) . '" value ="' . htmlspecialchars( $cur_value ) . '" size="30"/>' .
386 - '<span id="info_' . $sfgFieldNum . '" class="errorMessage"></span>';
387409
388 - return array( $html, $jstext );
389 -}
 410+ // call common setup for all jqdatepickers
 411+ self::jqDatePickerSetup();
390412
391 -/*
392 - * Definition of input type "datepicker".
393 - */
394 -static function datePickerHTML ( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {
 413+ // first: set up HTML attributes
395414
396 - global $wgRequest, $wgUser, $wgParser, $wgOut, $wgScriptPath;
 415+ // array of attributes to pass to the input field
 416+ $attribs = array(
 417+ "class" => "createboxInput",
 418+ "value" => $cur_value,
 419+ "type" => "text"
 420+ );
397421
398 - global $sfgTabIndex; // used to represent the current tab index in the form
399 - global $sfgFieldNum; // used for setting various HTML IDs
400 - global $sfgJSValidationCalls; // array of Javascript calls to determine if page can be saved
401422
402 - global $sfigSettings;
 423+ // set size attrib
 424+ if ( array_key_exists( 'size', $other_args ) ) $attribs['size'] = $other_args['size'];
403425
404 - if ( !( array_key_exists( 'hidden', $other_args ) || $is_disabled ) ) self::datePickerSetup();
 426+ // set maxlength attrib
 427+ if ( array_key_exists( 'maxlength', $other_args ) ) $attribs['maxlength'] = $other_args['maxlength'];
405428
406 - // set size string
407 - if ( array_key_exists( 'size', $other_args ) ) $sizeString = 'size="' . htmlspecialchars( $other_args['size'] ) . '" ';
408 - else $sizeString = '';
409429
410 - // set maxlength string
411 - if ( array_key_exists( 'maxlength', $other_args ) ) $maxlengthString = 'maxlength="' . htmlspecialchars( $other_args['maxlength'] ) . '" ';
412 - else $maxlengthString = '';
 430+ // modify class attribute for mandatory form fields
 431+ if ( $is_mandatory ) $attribs["class"] .= ' mandatory';
413432
414 - // set mandatory string
415 - if ( $is_mandatory ) $mandatoryString = 'mandatory ';
416 - else $mandatoryString = '';
 433+ // add user class(es) to class attribute of input field and to all other datepicker components
 434+ if ( array_key_exists( 'class', $other_args ) ) {
 435+ $attribs["class"] .= ' ' . $other_args['class'];
 436+ $userClasses = $other_args['class'];
 437+ }
417438
418 - // set class string
419 - if ( array_key_exists( 'class', $other_args ) ) {
420 - $classString = $other_args['class'];
421 - } else {
422 - $classString = '';
423 - }
 439+ // set readonly attrib
 440+ if ( array_key_exists( 'disable input field', $other_args )
 441+ || ( !array_key_exists( 'enable input field', $other_args ) && $sfigSettings->datePickerDisableInputField )
 442+ || $is_disabled ) {
424443
425 - // set input field disabled string
426 - if ( array_key_exists( 'disable input field', $other_args ) ) {
427 - $disableInputString = 'readonly ';
428 - } elseif ( array_key_exists( 'enable input field', $other_args ) ) {
429 - $disableInputString = '';
430 - } elseif ( $sfigSettings->datePickerDisableInputField ) {
431 - $disableInputString = 'readonly ';
432 - } else {
433 - $disableInputString = '';
434 - }
 444+ $attribs["readonly"] = "1";
435445
436 - // set week start string
437 - if ( array_key_exists( 'week start', $other_args ) ) {
438 - $weekStartString = $other_args['week start'];
439 - } else {
440 - $weekStartString = $sfigSettings->datePickerWeekStart;
441 - }
 446+ }
442447
443 - // set show week number string
444 - if ( array_key_exists( 'show week numbers', $other_args ) ) {
445 - $weekNumberString = 'true';
446 - } elseif ( array_key_exists( 'hide week numbers', $other_args ) ) {
447 - $weekNumberString = 'false';
448 - } elseif ( $sfigSettings->datePickerShowWeekNumbers ) {
449 - $weekNumberString = 'true';
450 - } else {
451 - $weekNumberString = 'false';
452 - }
 448+ // second: set up JS attributes, but only if we need them
 449+ if ( !$is_disabled ) {
453450
454 - // set disabled days of week
455 - if ( array_key_exists( 'disable days of week', $other_args ) && preg_match( '/^[0-6](,[0-6])*$/x', $other_args['disable days of week'] ) ) {
456 - $disabledDaysOfWeek = $other_args['disable days of week'];
457 - } else {
458 - $disabledDaysOfWeek = $sfigSettings->datePickerDisabledDaysOfWeek;
459 - }
 451+ // find min date, max date and disabled dates
460452
461 - // set highlighted days of week
462 - if ( array_key_exists( 'highlight days of week', $other_args ) && preg_match( '/^[0-6](,[0-6])*$/x', $other_args['highlight days of week'] ) ) {
463 - $highlightedDaysOfWeek = $other_args['highlight days of week'];
464 - } else {
465 - $highlightedDaysOfWeek = $sfigSettings->datePickerHighlightedDaysOfWeek;
466 - }
 453+ // set first date
 454+ if ( array_key_exists( 'first date', $other_args ) ) $minDate = date_create( $other_args['first date'] );
 455+ elseif ( $sfigSettings->datePickerFirstDate ) $minDate = date_create( $sfigSettings->datePickerFirstDate );
 456+ else $minDate = null;
467457
468 - // set first date
469 - if ( array_key_exists( 'first date', $other_args ) ) {
470 - $firstDateInString = $other_args['first date'];
471 - } elseif ( $sfigSettings->datePickerFirstDate ) {
472 - $firstDateInString = $sfigSettings->datePickerFirstDate;
473 - } else {
474 - $firstDateInString = null;
475 - }
476458
477 - if ( $firstDateInString ) {
478 - $parts = explode( '/', $firstDateInString );
479 - $firstDate = date_create( $parts[2] . '/' . $parts[1] . '/' . $parts[0] );
480 - } else $firstDate = null;
481459
482 - // set last date
483 - if ( array_key_exists( 'last date', $other_args ) ) {
484 - $lastDateInString = $other_args['last date'];
485 - } elseif ( $sfigSettings->datePickerLastDate ) {
486 - $lastDateInString = $sfigSettings->datePickerLastDate;
487 - } else {
488 - $lastDateInString = null;
489 - }
 460+ // set last date
 461+ if ( array_key_exists( 'last date', $other_args ) ) $maxDate = date_create( $other_args['last date'] );
 462+ elseif ( $sfigSettings->datePickerLastDate ) $maxDate = date_create( $sfigSettings->datePickerLastDate );
 463+ else $maxDate = null;
490464
491 - if ( $lastDateInString ) {
492 - $parts = explode( '/', $lastDateInString );
493 - $lastDate = date_create( $parts[2] . '/' . $parts[1] . '/' . $parts[0] );
494 - } else {
495 - $lastDate = null;
496 - }
 465+ // $disabledDates = null;
497466
498 - // set disabled days
499 - if ( array_key_exists( 'disable dates', $other_args ) ) {
500 - $disabledDates = $other_args['disable dates'];
501 - } else {
502 - $disabledDates = $sfigSettings->datePickerDisabledDates;
503 - }
 467+ // find possible values and invert them to get disabled values
 468+ if ( array_key_exists( 'possible_values', $other_args ) && count( $other_args['possible_values'] ) ) {
504469
505 - $disabledDatesString = '';
 470+ $enabledDates = self::sortAndMergeRanges( self::createRangesArray( $other_args['possible_values'] ) );
506471
507 - if ( $disabledDates ) {
 472+ // correct min/max date to the first/last allowed value
 473+ if ( !$minDate || $minDate < $enabledDates[0][0] ) $minDate = $enabledDates[0][0];
 474+ if ( !$maxDate || $maxDate > $enabledDates[count( $enabledDates ) - 1][1] ) $maxDate = $enabledDates[count( $enabledDates ) - 1][1];
508475
509 - foreach ( explode( ',', $disabledDates ) as $range ) {
510 - if ( strpos( $range, '-' ) === false ) {
511 - $dateArray = explode( '/', $range );
512 - $disabledDatesString .=
513 - Xml::encodeJsVar( $dateArray[1] . '/' .
514 - $dateArray[0] . '/' .
515 - $dateArray[2] ) . ', ';
 476+ $disabledDates = self::invertRangesArray( $enabledDates );
 477+
 478+ } else $disabledDates = array();
 479+
 480+ // add user-defined disabled values
 481+ if ( array_key_exists( 'disable dates', $other_args ) ) {
 482+
 483+ $disabledDates =
 484+ self::sortAndMergeRanges(
 485+ array_merge( $disabledDates, self::createRangesArray( explode( ',' , $other_args['disable dates'] ) ) ) );
 486+
 487+ } elseif ( $sfigSettings->datePickerDisabledDates ) {
 488+
 489+ $disabledDates =
 490+ self::sortAndMergeRanges(
 491+ array_merge( $disabledDates, self::createRangesArray( explode( ',' , $sfigSettings->datePickerDisabledDates ) ) ) );
 492+
 493+ }
 494+
 495+ if ( $minDate ) {
 496+ // discard all disabled dates below the min date
 497+ while ( $minDate && count( $disabledDates ) && $disabledDates[0][1] < $minDate ) array_shift( $disabledDates );
 498+
 499+ // if min date is in first disabled date range, discard that range and adjust min date
 500+ if ( count( $disabledDates ) && $disabledDates[0][0] <= $minDate && $disabledDates[0][1] >= $minDate ) {
 501+ $minDate = $disabledDates[0][1];
 502+ array_shift( $disabledDates );
 503+ $minDate->modify( "+1 day" );
 504+ }
 505+ }
 506+
 507+ if ( $maxDate ) {
 508+ // discard all disabled dates above the max date
 509+ while ( count( $disabledDates ) && $disabledDates[count( $disabledDates ) - 1][0] > $maxDate ) array_pop( $disabledDates );
 510+
 511+ // if max date is in last disabled date range, discard that range and adjust max date
 512+ if ( count( $disabledDates ) && $disabledDates[count( $disabledDates ) - 1][0] <= $maxDate && $disabledDates[count( $disabledDates ) - 1][1] >= $maxDate ) {
 513+ $maxDate = $disabledDates[count( $disabledDates ) - 1][0];
 514+ array_pop( $disabledDates );
 515+ $maxDate->modify( "-1 day" );
 516+ }
 517+ }
 518+ // finished with disabled dates
 519+
 520+ // find highlighted dates
 521+ if ( array_key_exists( "highlight dates", $other_args ) ) {
 522+ $highlightedDates = self::sortAndMergeRanges ( self::createRangesArray( explode( ',' , $other_args["highlight dates"] ) ) ) ;
 523+ } else if ( $sfigSettings->datePickerHighlightedDates ) {
 524+ $highlightedDates = self::sortAndMergeRanges ( self::createRangesArray( explode( ',' , $sfigSettings->datePickerHighlightedDates ) ) ) ;
516525 } else {
517 - $dateArray = explode( '/', str_replace( '-', '/', $range ) );
518 - $disabledDatesString .=
519 - Xml::encodeJsVar( $dateArray[1] . '/' .
520 - $dateArray[0] . '/' .
521 - $dateArray[2] . '-' .
522 - $dateArray[4] . '/' .
523 - $dateArray[3] . '/' .
524 - $dateArray[5] ) . ', ';
 526+ $highlightedDates = null;
525527 }
526 - }
527528
528 - }
529529
530 - if ( array_key_exists( 'possible_values', $other_args ) && $other_args['possible_values'] ) {
 530+ // find disabled week days and mark them in an array
 531+ if ( array_key_exists( "disable days of week", $other_args ) ) $disabledDaysString = $other_args['disable days of week'];
 532+ else $disabledDaysString = $sfigSettings->datePickerDisabledDaysOfWeek;
531533
532 - $enabledDates = array(); // stores enabled date ranges, i.e. arrays containing first and last enabled day
 534+ if ( $disabledDaysString != null ) {
533535
534 - foreach ( $other_args['possible_values'] as $range ) {
 536+ $disabledDays = array( false, false, false, false, false, false, false );
535537
536 - if ( strpos( $range, '-' ) === false )
537 - $enabledDates[] = array( date_create( str_replace( '/', '-', $range ) ), // need '-' to correctly parse dates
538 - date_create( str_replace( '/', '-', $range ) ) );
539 - else
540 - $enabledDates[] = array_map( "date_create",
541 - explode( ':', str_replace( '/', '-', str_replace( '-', ':', $range ) ) ) );
 538+ foreach ( explode( ',', $disabledDaysString ) as $day ) {
542539
543 - }
 540+ if ( is_numeric( $day ) && $day >= 0 && $day <= 6 ) {
 541+ $disabledDays[$day] = true;
 542+ }
544543
545 - sort( $enabledDates );
 544+ }
546545
547 - // adjust first year
548 - // if (array_key_exists('years from values', $other_args) && array_key_exists(0, $enabledDates))
549 - if ( count( $enabledDates ) > 0 && ( !$firstDate || $firstDate < $enabledDates[0][0] ) ) {
550 - $firstDate = $enabledDates[0][0];
551 - }
 546+ } else {
 547+ $disabledDays = null;
 548+ }
552549
553 - $prevStartOfDisabled = $firstDate;
 550+ // find highlighted week days and mark them in an array
 551+ if ( array_key_exists( "highlight days of week", $other_args ) ) $highlightedDaysString = $other_args['highlight days of week'];
 552+ else $highlightedDaysString = $sfigSettings->datePickerHighlightedDaysOfWeek;
554553
555 - // from the list of enabled dates create a list of disabled dates
556 - while ( list( $currKey, $currRange ) = each( $enabledDates ) ) {
557554
558 - $currEndOfDisabled = clone $enabledDates[$currKey][0];
559 - $currEndOfDisabled->modify( "-1 day" );
 555+ if ( $highlightedDaysString != null ) {
560556
561 - $currStartOfDisabled = clone $enabledDates[$currKey][1];
562 - $currStartOfDisabled->modify( "+1 day" );
 557+ $highlightedDays = array( false, false, false, false, false, false, false );
563558
564 - if ( $currEndOfDisabled <= $prevStartOfDisabled ) {
565 - $prevStartOfDisabled = max( $currStartOfDisabled, $prevStartOfDisabled );
 559+ foreach ( explode( ',', $highlightedDaysString ) as $day ) {
 560+
 561+ if ( is_numeric( $day ) && $day >= 0 && $day <= 6 ) {
 562+ $highlightedDays[$day] = true;
 563+ }
 564+
 565+ }
566566 } else {
 567+ $highlightedDays = null;
 568+ }
567569
568 - $disabledDatesString .= '"' .
569 - $prevStartOfDisabled->format( 'n' ) . '/' .
570 - $prevStartOfDisabled->format( 'j' ) . '/' .
571 - $prevStartOfDisabled->format( 'Y' ) . '-' .
572 - $currEndOfDisabled->format( 'n' ) . '/' .
573 - $currEndOfDisabled->format( 'j' ) . '/' .
574 - $currEndOfDisabled->format( 'Y' ) . '", ';
 570+ // set datepicker widget attributes
 571+ $jsattribs = array(
 572+ 'showOn' => 'both',
 573+ 'buttonImage' => $sfigSettings->scriptPath . '/DatePickerButton.gif',
 574+ 'buttonImageOnly' => false,
 575+ 'changeMonth' => true,
 576+ 'changeYear' => true,
 577+ 'altField' => "#input_{$sfgFieldNum}",
 578+ 'altFormat' => "yy/mm/dd",
 579+ // Today button does not work (http://dev.jqueryui.com/ticket/4045)
 580+ // do not show button panel for now
 581+ // TODO: show date picker button panel when bug is fixed
 582+ 'showButtonPanel' => false
 583+ );
575584
576 - $prevStartOfDisabled = $currStartOfDisabled;
 585+ // set first day of the week
 586+ if ( array_key_exists( 'week start', $other_args ) ) $jsattribs['firstDay'] = $other_args['week start'];
 587+ else if ( $sfigSettings->datePickerWeekStart != null ) $jsattribs['firstDay'] = $sfigSettings->datePickerWeekStart;
 588+ else $jsattribs['firstDay'] = wfMsg( 'semanticformsinputs-firstdayofweek' );
577589
 590+ // set show week number
 591+ if ( array_key_exists( 'show week numbers', $other_args )
 592+ || ( !array_key_exists( 'hide week numbers', $other_args ) && $sfigSettings->datePickerShowWeekNumbers ) ) {
 593+
 594+ $jsattribs['showWeek'] = true;
 595+
578596 }
579 - }
580597
 598+ // set date format
 599+ if ( $wgAmericanDates && $wgLang->getCode() == "en" ) {
581600
582 - // adjust last date
583 - if ( !$lastDate || $lastDate > $prevStartOfDisabled ) {
584 - $lastDate = $prevStartOfDisabled;
585 - }
 601+ if ( array_key_exists( 'date format', $other_args ) ) {
586602
587 - }
 603+ if ( $other_args['date format'] == 'SHORT' ) $jsattribs['dateFormat'] = 'mm/dd/yy';
 604+ elseif ( $other_args['date format'] == 'LONG' ) $jsattribs['dateFormat'] = 'MM d, yy';
 605+ else $jsattribs['dateFormat'] = $other_args['date format'];
588606
589 - // set disabled dates string
590 - if ( $disabledDatesString ) {
591 - $disabledDatesString = rtrim( $disabledDatesString, ", " );
592 - }
 607+ } elseif ( $sfigSettings->datePickerDateFormat ) {
593608
594 - // set first date string and last date string
595 - if ( $firstDate ) {
596 - $firstDateString =
597 - $firstDate->format( 'n' ) . '/' .
598 - $firstDate->format( 'j' ) . '/' .
599 - $firstDate->format( 'Y' );
600 - } else {
601 - $firstDateString = 'null';
602 - }
 609+ if ( $sfigSettings->datePickerDateFormat == 'SHORT' ) $jsattribs['dateFormat'] = 'mm/dd/yy';
 610+ elseif ( $sfigSettings->datePickerDateFormat == 'LONG' ) $jsattribs['dateFormat'] = 'MM d, yy';
 611+ else $jsattribs['dateFormat'] = $sfigSettings->datePickerDateFormat;
603612
604 - if ( $lastDate ) {
605 - $lastDateString =
606 - $lastDate->format( 'n' ) . '/' .
607 - $lastDate->format( 'j' ) . '/' .
608 - $lastDate->format( 'Y' );
609 - } else {
610 - $lastDateString = 'null';
611 - }
 613+ } else $jsattribs['dateFormat'] = 'yy/mm/dd';
612614
613 - // set highlighted dates
614 - if ( array_key_exists( 'highlight dates', $other_args ) ) {
615 - $highlightedDates = $other_args['highlight dates'];
616 - } else {
617 - $highlightedDates = $sfigSettings->datePickerHighlightedDates;
618 - }
 615+ } else {
619616
620 - $highlightedDatesString = '';
 617+ if ( array_key_exists( 'date format', $other_args ) ) {
621618
622 - if ( $highlightedDates ) {
 619+ if ( $other_args['date format'] == 'SHORT' ) $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatshort' );
 620+ elseif ( $other_args['date format'] == 'LONG' ) $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatlong' );
 621+ else $jsattribs['dateFormat'] = $other_args['date format'];
623622
624 - foreach ( explode( ',', $highlightedDates ) as $range ) {
625 - if ( strpos( $range, '-' ) === false ) {
626 - $dateArray = explode( '/', $range );
627 - $highlightedDatesString .=
628 - Xml::encodeJsVar( $dateArray[1] . '/' .
629 - $dateArray[0] . '/' .
630 - $dateArray[2] ) . ', ';
631 - } else {
632 - $dateArray = explode( '/', str_replace( '-', '/', $range ) );
633 - $highlightedDatesString .=
634 - Xml::encodeJsVar( $dateArray[1] . '/' .
635 - $dateArray[0] . '/' .
636 - $dateArray[2] . '-' .
637 - $dateArray[4] . '/' .
638 - $dateArray[3] . '/' .
639 - $dateArray[5] ) . ', ';
 623+ } elseif ( $sfigSettings->datePickerDateFormat ) {
 624+
 625+ if ( $sfigSettings->datePickerDateFormat == 'SHORT' ) $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatshort' );
 626+ elseif ( $sfigSettings->datePickerDateFormat == 'LONG' ) $jsattribs['dateFormat'] = wfMsg( 'semanticformsinputs-dateformatlong' );
 627+ else $jsattribs['dateFormat'] = $sfigSettings->datePickerDateFormat;
 628+
 629+ } else $jsattribs['dateFormat'] = 'yy/mm/dd';
 630+
640631 }
 632+
641633 }
642634
643 - $highlightedDatesString = rtrim( $highlightedDatesString, ", " );
644635
645 - }
 636+ // third: build HTML and JS code
646637
647 - // set date format string
648 - if ( array_key_exists( 'date format', $other_args ) ) {
649 - $dateFormatString = $other_args['date format'];
650 - }
651 - else $dateFormatString = $sfigSettings->datePickerDateFormat;
652638
653 - // set default date string
654 - $defaultDateString = 'null';
 639+ if ( $is_disabled ) {
655640
656 - // set month strings
657 - if ( array_key_exists( 'month names', $other_args ) ) {
658 - $monthNames = $other_args['month names'];
659 - } else {
660 - $monthNames = $sfigSettings->datePickerMonthNames;
661 - }
 641+ $attribs[ 'id' ] = "input_{$sfgFieldNum}";
 642+ $attribs[ 'name' ] = $input_name;
662643
663 - // set day strings
664 - if ( array_key_exists( 'day names', $other_args ) ) {
665 - $dayNames = Xml::encodeJsVar( $other_args['day names'] );
666 - } else {
667 - $dayNames = $sfigSettings->datePickerDayNames;
668 - }
 644+ // no JS needed on a disabled datepicker, but we need to append the disabled button ourselves
 645+ $html = Html::element( "input", $attribs )
 646+ . Html::rawElement( "button",
 647+ array(
 648+ 'type' => 'button',
 649+ 'class' => $userClasses,
 650+ 'disabled' => '1',
 651+ 'id' => "input_{$sfgFieldNum}_button"
 652+ ),
 653+ Html::element( "image",
 654+ array( 'src' => $sfigSettings->scriptPath . '/DatePickerButtonDisabled.gif' )
669655
670 - // set show reset button string
671 - if ( array_key_exists( 'show reset button', $other_args ) ) {
672 - $showResetButton = true;
673 - } elseif ( array_key_exists( 'hide reset button', $other_args ) ) {
674 - $showresetbutton = false;
675 - } else {
676 - $showResetButton = $sfigSettings->datePickerShowResetButton;
677 - }
 656+ )
 657+ );
678658
679 - $classString = htmlspecialchars( $classString );
680 - $cur_value = htmlspecialchars( $cur_value );
681 - // $mandatoryString: contains a fixed string ("mandatory ", "")
682 - $input_name = htmlspecialchars( $input_name );
683 - // $sizeString: already sanitized
684 - // $maxlengthString: already sanitized
685 - // $disableInputString: contains a fixed string ("readonly ", "")
 659+ // append reset button if required
 660+ if ( array_key_exists( 'show reset button', $other_args ) ||
 661+ $sfigSettings->datePickerShowResetButton && !array_key_exists( 'hide reset button', $other_args ) ) {
686662
687 - if ( $showResetButton && $is_disabled ) {
 663+ $html .= Html::rawElement( "button",
 664+ array(
 665+ 'type' => 'button',
 666+ 'class' => $userClasses,
 667+ 'disabled' => '1',
 668+ 'id' => "input_{$sfgFieldNum}_resetbutton"
 669+ ),
 670+ Html::element( "image",
 671+ array( 'src' => $sfigSettings->scriptPath . '/DatePickerResetButtonDisabled.gif' )
 672+ )
 673+ );
688674
689 - $resetButtonString =
690 - '<button tabindex="-1" type=button id="input_' . $sfgFieldNum . '_resetbutton" class="' . $classString . '" onclick="return false;" ' .
691 - 'style="height:1.5em;width:1.5em; vertical-align:middle;background-image: url(' . $sfigSettings->scriptPath . '/DatePickerResetButtonDisabled.gif);' .
692 - 'background-position: center center; background-repeat: no-repeat;" disabled ></button>';
 675+ }
693676
694 - } elseif ( $showResetButton ) {
 677+ // no JS needed on a disabled datepicker
 678+ $jstext = '';
695679
696 - $resetButtonString =
697 - '<button tabindex="-1" type=button id="input_' . $sfgFieldNum . '_resetbutton" class="' . $classString . '" onclick="reset_datepicker(this);" ' .
698 - 'style="height:1.5em;width:1.5em;vertical-align:middle;background-image: url(' . $sfigSettings->scriptPath . '/DatePickerResetButton.gif);' .
699 - 'background-position: center center; background-repeat: no-repeat;" ></button>';
700 - } else {
701 - $resetButtonString = "";
702 - }
 680+ } else {
703681
704 - // compose html text
705 - if ( array_key_exists( 'hidden', $other_args ) ) {
 682+ $attribs[ 'id' ] = "input_{$sfgFieldNum}_show";
 683+ $attribs[ 'tabindex' ] = $sfgTabIndex;
706684
707 - $htmltext = '<input type="hidden" id="input_' . $sfgFieldNum
708 - . '" value="' . $cur_value
709 - . '" class="createboxInput ' . $mandatoryString . $classString
710 - . '" name="' . $input_name . '" /><span id="info_' . $sfgFieldNum
711 - . '" class="errorMessage"></span>';
 685+ // start with the displayed input and
 686+ // append the real, but hidden input that gets sent to SF;
 687+ // it will be filled by the datepicker
 688+ $html = Html::element( "input", $attribs )
 689+ . Html::element( "input",
 690+ array(
 691+ "id" => "input_{$sfgFieldNum}",
 692+ "name" => $input_name,
 693+ "type" => "hidden"
 694+ )
 695+ );
712696
713 - } elseif ( $is_disabled ) {
714 - $htmltext =
715 - '<span class="yui-skin-sam">'
716 - . '<input type="text" ' . $sizeString . $maxlengthString
717 - . ' id="input_' . $sfgFieldNum . '" ' . 'value="' . $cur_value
718 - . '" class="createboxInput ' . $mandatoryString . $classString . '" '
719 - . 'style="vertical-align:middle;" name="' . $input_name . '" readonly />'
720 - . '<button tabindex="-1" type=button id="input_' . $sfgFieldNum
721 - . '_button" class="' . $classString . '" onclick="return false;" '
722 - . 'style="height:1.5em;width:1.5em;vertical-align:middle;background-image: url('
723 - . $sfigSettings->scriptPath . '/DatePickerButtonDisabled.gif);'
724 - . 'background-position: center center; background-repeat: no-repeat;" disabled ></button>' .
725 - $resetButtonString . "\n"
726 - . '<span id="info_' . $sfgFieldNum . '" class="errorMessage"></span>'
727 - . '</span>';
 697+ // append reset button if required
 698+ if ( array_key_exists( 'show reset button', $other_args ) ||
 699+ $sfigSettings->datePickerShowResetButton && !array_key_exists( 'hide reset button', $other_args ) ) {
728700
729 - } else { // not hidden, not disabled
730 - $htmltext =
731 - '<span class="yui-skin-sam">'
732 - . '<span id="input_' . $sfgFieldNum
733 - . '_container" style="position:absolute;display:inline;margin-top:2em;">'
734 - . '<span id="input_' . $sfgFieldNum . '_calendar"></span></span>'
735 - . '<input type="text" ' . $sizeString . $maxlengthString . $disableInputString
736 - . ' id="input_' . $sfgFieldNum . '" ' . 'value="' . $cur_value
737 - . '" class="createboxInput ' . $mandatoryString . $classString . '" '
738 - . 'style="vertical-align:middle;" name="' . $input_name . '" />'
739 - . '<button tabindex="-1" type=button id="input_' . $sfgFieldNum
740 - . '_button" class="' . $classString . '" onclick="toggle_datepicker(this);" '
741 - . 'style="height: 1.5em; width: 1.5em;vertical-align:middle;background-image: url('
742 - . $sfigSettings->scriptPath . '/DatePickerButton.gif);'
743 - . 'background-position: center center; background-repeat: no-repeat;" ></button>'
744 - . $resetButtonString . "\n"
745 - . '<span id="info_' . $sfgFieldNum . '" class="errorMessage"></span>'
746 - . '</span>';
747 - }
 701+ $html .= "<button "
 702+ . Html::expandAttributes ( array(
 703+ 'type' => 'button',
 704+ 'class' => $userClasses,
 705+ 'id' => "input_{$sfgFieldNum}_resetbutton",
 706+ ) )
 707+ . "onclick= \"document.getElementById('input_{$sfgFieldNum}').value='';document.getElementById('input_{$sfgFieldNum}_show').value='';\""
 708+ . ">"
 709+ . Html::element( "image", array( 'src' => $sfigSettings->scriptPath . '/DatePickerResetButton.gif' ) )
 710+ . "</button>";
748711
749 - // compose Javascript
750 - if ( array_key_exists( 'hidden', $other_args ) || $is_disabled ) {
751 - $jstext = '';
752 - } else {
 712+ }
753713
754 - $weekStartString = htmlspecialchars( Xml::encodeJsVar( $weekStartString ), ENT_NOQUOTES );
755 - // $weekNumberString: contains a fixed string ("true", "false")
756 - // $disabledDaysOfWeek: input filtered, only numbers and commas allowed
757 - // $highlightedDaysOfWeek: input filtered, only numbers and commas allowed
758 - $disabledDatesString = htmlspecialchars( $disabledDatesString, ENT_NOQUOTES ); // Js sanitized on input
759 - $highlightedDatesString = htmlspecialchars( $highlightedDatesString, ENT_NOQUOTES ); // Js sanitized on input
 714+ $cur_value = Xml::escapeJsString( $cur_value );
760715
761 - if ( strcmp( $firstDateString, "null" ) ) {
762 - $firstDateString = htmlspecialchars( Xml::encodeJsVar( $firstDateString ), ENT_NOQUOTES );
763 - }
764716
765 - if ( strcmp( $lastDateString, "null" ) ) {
766 - $lastDateString = htmlspecialchars( Xml::encodeJsVar( $lastDateString ), ENT_NOQUOTES );
767 - }
 717+ // build JS array
 718+ $jsattribsString = Xml::encodeJsVar( $jsattribs );
768719
769 - if ( strcmp( $defaultDateString, "null" ) ) {
770 - $defaultDateString = htmlspecialchars( Xml::encodeJsVar( $defaultDateString ), ENT_NOQUOTES );
771 - }
 720+ // attach datepicker to input field
 721+ $jstext = <<<JAVASCRIPT
 722+ jQuery (
 723+ function() {
 724+ jQuery("#input_{$sfgFieldNum}_show").datepicker( $jsattribsString );
 725+ jQuery("#input_{$sfgFieldNum}_show").datepicker( "setDate", jQuery.datepicker.parseDate("yy/mm/dd", "$cur_value", null) );
772726
773 - $monthNames = htmlspecialchars( Xml::encodeJsVar( $monthNames ), ENT_NOQUOTES );
774 - $dayNames = htmlspecialchars( Xml::encodeJsVar( $dayNames ), ENT_NOQUOTES );
775 - $dateFormatString = htmlspecialchars( Xml::encodeJsVar( $dateFormatString ), ENT_NOQUOTES );
 727+JAVASCRIPT;
776728
777 - $jstext = <<<JAVASCRIPT
778 - function setup_input_{$sfgFieldNum}() {
 729+ // set first date
 730+ if ( $minDate ) {
779731
780 - sfiElements['settings_$sfgFieldNum'] = new Object();
781 - sfiElements['settings_$sfgFieldNum'].start_weekday = $weekStartString;
782 - sfiElements['settings_$sfgFieldNum'].show_week_header = $weekNumberString;
783 - sfiElements['settings_$sfgFieldNum'].disabled_days_of_week = [$disabledDaysOfWeek];
784 - sfiElements['settings_$sfgFieldNum'].highlighted_days_of_week = [$highlightedDaysOfWeek];
785 - sfiElements['settings_$sfgFieldNum'].disabled_days = [$disabledDatesString];
786 - sfiElements['settings_$sfgFieldNum'].highlighted_days = [$highlightedDatesString];
787 - sfiElements['settings_$sfgFieldNum'].first_day = $firstDateString;
788 - sfiElements['settings_$sfgFieldNum'].last_day = $lastDateString;
789 - sfiElements['settings_$sfgFieldNum'].default_day = $defaultDateString;
790 - sfiElements['settings_$sfgFieldNum'].locale_months = $monthNames;
791 - sfiElements['settings_$sfgFieldNum'].locale_weekdays = $dayNames;
792 - sfiElements['settings_$sfgFieldNum'].date_format = $dateFormatString;
 732+ $minDateString = $minDate->format( 'Y-m-d' );
 733+ $jstext .= <<<JAVASCRIPT
 734+ jQuery("#input_{$sfgFieldNum}_show").datepicker( "option", "minDate", jQuery.datepicker.parseDate("yy/mm/dd", "$minDateString", null) );
793735
 736+JAVASCRIPT;
 737+ }
 738+
 739+ // set last date
 740+ if ( $maxDate ) {
 741+
 742+ $maxDateString = $maxDate->format( 'Y-m-d' );
 743+
 744+ $jstext .= <<<JAVASCRIPT
 745+ jQuery("#input_{$sfgFieldNum}_show").datepicker( "option", "maxDate", jQuery.datepicker.parseDate("yy/mm/dd", "$maxDateString", null) );
 746+
 747+JAVASCRIPT;
 748+ }
 749+
 750+
 751+ // add user-defined class(es) to all datepicker components
 752+ if ( array_key_exists( 'class', $other_args ) ) {
 753+
 754+ $userClasses = Xml::encodeJsVar ( $userClasses );
 755+
 756+ $jstext .= <<<JAVASCRIPT
 757+ jQuery("#input_{$sfgFieldNum}_show").datepicker("widget").addClass({$userClasses});
 758+ jQuery("#input_{$sfgFieldNum}_show + button").addClass({$userClasses});
 759+
 760+JAVASCRIPT;
 761+
 762+ }
 763+
 764+ // register disabled dates
 765+ // attach event handler to handle disabled dates
 766+ if ( count( $disabledDates ) || count( $highlightedDates ) || count( $disabledDays ) || count( $highlightedDays ) ) {
 767+
 768+ // register disabled dates with datepicker
 769+ if ( count( $disabledDates ) ) {
 770+
 771+ $disabledDatesString = '[' . implode( ',', array_map( function ( $range ) {
 772+
 773+ $y0 = $range[0]->format( "Y" );
 774+ $m0 = $range[0]->format( "m" ) - 1;
 775+ $d0 = $range[0]->format( "d" );
 776+
 777+ $y1 = $range[1]->format( "Y" );
 778+ $m1 = $range[1]->format( "m" ) - 1;
 779+ $d1 = $range[1]->format( "d" );
 780+
 781+ return "[new Date({$y0}, {$m0}, {$d0}), new Date({$y1}, {$m1}, {$d1})]";
 782+ } , $disabledDates ) ) . ']';
 783+
 784+ $jstext .= " jQuery(\"#input_{$sfgFieldNum}_show\").datepicker(\"option\", \"disabledDates\", $disabledDatesString);\n";
 785+
 786+ }
 787+
 788+ // register highlighted dates with datepicker
 789+ if ( count( $highlightedDates ) ) {
 790+
 791+ $highlightedDatesString = '[' . implode( ',', array_map( function ( $range ) {
 792+
 793+ $y0 = $range[0]->format( "Y" );
 794+ $m0 = $range[0]->format( "m" ) - 1;
 795+ $d0 = $range[0]->format( "d" );
 796+
 797+ $y1 = $range[1]->format( "Y" );
 798+ $m1 = $range[1]->format( "m" ) - 1;
 799+ $d1 = $range[1]->format( "d" );
 800+
 801+ return "[new Date({$y0}, {$m0}, {$d0}), new Date({$y1}, {$m1}, {$d1})]";
 802+ } , $highlightedDates ) ) . ']';
 803+
 804+ $jstext .= " jQuery(\"#input_{$sfgFieldNum}_show\").datepicker(\"option\", \"highlightedDates\", $highlightedDatesString);\n";
 805+
 806+ }
 807+
 808+ // register disabled days of week with datepicker
 809+ if ( count( $disabledDays ) ) {
 810+ $disabledDaysString = Xml::encodeJsVar( $disabledDays );
 811+ $jstext .= " jQuery(\"#input_{$sfgFieldNum}_show\").datepicker(\"option\", \"disabledDays\", $disabledDaysString);\n";
 812+ }
 813+
 814+ // register highlighted days of week with datepicker
 815+ if ( count( $highlightedDays ) ) {
 816+ $highlightedDaysString = Xml::encodeJsVar( $highlightedDays );
 817+ $jstext .= " jQuery(\"#input_{$sfgFieldNum}_show\").datepicker(\"option\", \"highlightedDays\", $highlightedDaysString);\n";
 818+ }
 819+
 820+ $jstext .= <<<JAVASCRIPT
 821+
 822+ jQuery("#input_{$sfgFieldNum}_show").datepicker("option", "beforeShowDay", function (date) {return SFI_DP_checkDate(this, date);});
 823+
 824+JAVASCRIPT;
 825+ }
 826+
 827+ // close JS code fragment
 828+ $jstext .= <<<JAVASCRIPT
 829+ }
 830+ );
 831+
 832+JAVASCRIPT;
 833+
 834+
794835 }
795836
796 - addOnloadHook(setup_input_{$sfgFieldNum});
 837+ // add span for error messages (e.g. used for mandatory inputs)
 838+ $html .= Html::element( "span", array( "id" => "info_$sfgFieldNum", "class" => "errorMessage" ) );
797839
798 -JAVASCRIPT;
 840+ $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' );
 841+
 842+ return array( $html, "" );
 843+
799844 }
800 -
801 - return array( $htmltext, $jstext );
802845 }
803 -}
Index: trunk/extensions/SemanticFormsInputs/README
@@ -25,12 +25,6 @@
2626 Javascript library (version 2.7.0b or higher) must be available,
2727 either locally or via an existing internet connection.
2828
29 -(The HeaderTabs extension 0.6.6 seems to work with 2.7.0b with some
30 -small change in the HeaderTabs.php: Remove the if-clause in lines 118
31 -.. 126, then remove " . style" from line 127. The catch with that
32 -solution is, that the browser history feature of the Header Tabs will
33 -still not work, so you will have to deactivate it.)
34 -
3529 To install Semantic Forms Inputs, create a directory named
3630 SemanticFormsInputs in the extensions directory of your MediaWiki
3731 installation and copy the extension's files into it. Then add the
@@ -44,10 +38,7 @@
4539 Semantic Forms Inputs was written by Stephan Gambke, Sanyam Goyal and
4640 Yaron Koren.
4741
48 -The 'datepicker' input uses the Yahoo! User Interface (YUI) library.
49 -See http://developer.yahoo.com/yui/ .
50 -
51 -The 'simpledatepicker' input uses the jQuery and jQuery UI libraries.
 42+The 'datepicker' input uses the jQuery and jQuery UI libraries.
5243 See http://jquery.org/ and http://jqueryui.com/ .
5344
5445 Button icons are derived from the Mini Icons 2 icon set from
@@ -57,13 +48,16 @@
5849
5950 == Contact ==
6051
61 -Comments, questions, bug reports and suggestions can be send or posted
62 -to:
 52+Bugs should preferably be reported on the Wikimedia bug tracker:
 53+http://bugzilla.wikimedia.org/
6354
 55+Comments, questions and suggestions can be send or posted to:
 56+
6457 * the appropriate Semantic MediaWiki mailing list:
65 - http://sourceforge.net/projects/semediawiki/support
 58+ http://lists.sourceforge.net/lists/listinfo/semediawiki-user
6659
6760 * the Semantic Forms Inputs discussion page on mediawiki.org:
6861 http://www.mediawiki.org/wiki/Extension_talk:Semantic_Forms_Inputs
6962
70 -* Stephan Gambke: f.trott@gmx.net
 63+* the author:
 64+ http://www.mediawiki.org/wiki/Special:EmailUser/F.trott

Status & tagging log