Index: trunk/extensions/SemanticFormsInputs/SemanticFormsInputs.php |
— | — | @@ -4,8 +4,8 @@ |
5 | 5 | * |
6 | 6 | * @author Stephan Gambke |
7 | 7 | * @author Sanyam Goyal |
8 | | - * @version 0.3.1 |
9 | | - */ |
| 8 | + * @version 0.4 alpha |
| 9 | + */ |
10 | 10 | |
11 | 11 | if ( !defined( 'MEDIAWIKI' ) ) { |
12 | 12 | die( 'This file is a MediaWiki extension, it is not a valid entry point.' ); |
— | — | @@ -15,7 +15,7 @@ |
16 | 16 | die( 'This is a Semantic Forms extension. You need to install Semantic Forms first.' ); |
17 | 17 | } |
18 | 18 | |
19 | | -define( 'SFI_VERSION', '0.7.3 alpha' ); |
| 19 | +define( 'SFI_VERSION', '0.4 alpha' ); |
20 | 20 | |
21 | 21 | // create and initialize settings |
22 | 22 | $sfigSettings = new SFISettings(); |
— | — | @@ -30,10 +30,11 @@ |
31 | 31 | 'version' => SFI_VERSION, |
32 | 32 | ); |
33 | 33 | |
| 34 | +$dir = dirname( __FILE__ ); |
| 35 | + |
34 | 36 | // load user settings |
35 | | -require_once( 'SFI_Settings.php' ); |
| 37 | +require_once( $dir. '/SFI_Settings.php' ); |
36 | 38 | |
37 | | -$dir = dirname( __FILE__ ); |
38 | 39 | $wgExtensionMessagesFiles['SemanticFormsInputs'] = $dir . '/SemanticFormsInputs.i18n.php'; |
39 | 40 | $wgExtensionFunctions[] = "wfSFISetup"; |
40 | 41 | $wgAutoloadClasses['SFIInputs'] = $dir . '/SFI_Inputs.php'; |
— | — | @@ -71,6 +72,10 @@ |
72 | 73 | $sfgFormPrinter->setInputTypeHook( 'regexp', array( 'SFIInputs', 'regexpHTML' ), array() ); |
73 | 74 | $sfgFormPrinter->setInputTypeHook( 'datepicker', array( 'SFIInputs', 'jqDatePickerHTML' ), array() ); |
74 | 75 | $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() ); |
75 | 79 | |
76 | | - $wgOut->addInlineScript( 'sfiElements = new Object();' ); |
| 80 | + // TODO: obsolete as of MW 1.16, remove around 1.18 or so |
| 81 | + wfLoadExtensionMessages( 'SemanticFormsInputs' ); |
77 | 82 | } |
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 |
1 | 11 | + private |
Index: trunk/extensions/SemanticFormsInputs/SFI_Settings.php |
— | — | @@ -3,34 +3,34 @@ |
4 | 4 | * Settings for the Semantic Forms Inputs extension. |
5 | 5 | * |
6 | 6 | * @author Stephan Gambke |
7 | | - * @version 0.3.1 |
| 7 | + * @version 0.4 alpha |
8 | 8 | * |
9 | 9 | * To change the default settings you can uncomment (or copy) the |
10 | 10 | * examples here and adjust them to your needs. You may as well |
11 | 11 | * include them in your LocalSettings.php. |
12 | 12 | */ |
13 | 13 | |
14 | | -# # # |
| 14 | +## |
15 | 15 | # This is the path to your installation of Semantic Forms Inputs as |
16 | 16 | # seen from the web. No final slash. |
17 | | -# # |
| 17 | +# |
18 | 18 | $sfigSettings->scriptPath = $wgScriptPath . '/extensions/SemanticFormsInputs'; |
19 | 19 | |
20 | | -# # # Date Picker Settings |
| 20 | +## Date Picker Settings |
21 | 21 | |
22 | | -# # # |
| 22 | +## |
23 | 23 | # This is the first selectable date (format yyyy/mm/dd) |
24 | 24 | # Sample value: '2005/01/01' |
25 | | -# # |
| 25 | +# |
26 | 26 | $sfigSettings->datePickerFirstDate = null; |
27 | 27 | |
28 | | -# # # |
| 28 | +## |
29 | 29 | # This is the last selectable date (format yyyy/mm/dd) |
30 | 30 | # Sample value: '2015/31/12' |
31 | | -# # |
| 31 | +# |
32 | 32 | $sfigSettings->datePickerLastDate = null; |
33 | 33 | |
34 | | -# # # |
| 34 | +## |
35 | 35 | # The date format string used for the user input. |
36 | 36 | # The date sent back to the form is fixed to yyyy/mm/dd |
37 | 37 | # (that is, yy/mm/dd in the format code below). |
— | — | @@ -71,63 +71,91 @@ |
72 | 72 | # TICKS - '!' |
73 | 73 | # TIMESTAMP - '@' |
74 | 74 | # W3C - 'yy-mm-dd' (Same as ISO 8601) |
75 | | -# # |
| 75 | +# |
76 | 76 | $sfigSettings->datePickerDateFormat = 'SHORT'; |
77 | 77 | |
78 | | -# # # |
| 78 | +## |
79 | 79 | # This determines the start of the week in the display. |
80 | 80 | # Set it to: 0 (Zero) for Sunday, 1 (One) for Monday etc. |
81 | 81 | # If set to null the day is localized to the wiki user language |
82 | 82 | # Sample value: 1 |
83 | | -# # |
| 83 | +# |
84 | 84 | $sfigSettings->datePickerWeekStart = null; |
85 | 85 | |
86 | | -# # # |
| 86 | +## |
87 | 87 | # This determines if the number of the week shall be shown. |
88 | | -# # |
| 88 | +# |
89 | 89 | $sfigSettings->datePickerShowWeekNumbers = false; |
90 | 90 | |
91 | | -# # # |
| 91 | +## |
92 | 92 | # This determines if the input field shall be disabled. The user can |
93 | 93 | # only set the date via the datepicker in this case. |
94 | | -# # |
| 94 | +# |
95 | 95 | $sfigSettings->datePickerDisableInputField = false; |
96 | 96 | |
97 | | -# # # |
| 97 | +## |
98 | 98 | # This determines if a reset button shall be shown. This is the only |
99 | 99 | # way to erase the input field if it is disabled for direct input. |
100 | | -# # |
| 100 | +# |
101 | 101 | $sfigSettings->datePickerShowResetButton = false; |
102 | 102 | |
103 | | -# # # |
| 103 | +## |
104 | 104 | # This is a string of disabled days of the week, i.e. days the user can not |
105 | 105 | # pick. The days must be given as comma-separated list of numbers starting |
106 | 106 | # with 0 for Sunday. |
107 | 107 | # Sample value: "6,0" |
108 | | -# # |
| 108 | +# |
109 | 109 | $sfigSettings->datePickerDisabledDaysOfWeek = null; |
110 | 110 | |
111 | | -# # # |
| 111 | +## |
112 | 112 | # This is a string of highlighted days of the week. The days must be given as |
113 | 113 | # comma-separated list of numbers starting with 0 for Sunday. |
114 | 114 | # Sample value: "6,0" |
115 | | -# # |
| 115 | +# |
116 | 116 | $sfigSettings->datePickerHighlightedDaysOfWeek = null; |
117 | 117 | |
118 | | -# # # |
| 118 | +## |
119 | 119 | # This is a string of disabled dates, i.e. days the user cannot pick. The |
120 | 120 | # days must be given as comma-separated list of dates or date ranges. The |
121 | 121 | # format for days is yyyy/mm/dd, for date ranges use yyyy/mm/dd-yyyy/mm/dd. |
122 | 122 | # Spaces are permissible. |
123 | 123 | # Sample value: "2010/12/25 - 2011/01/06, 2011/05/01" |
124 | | -# # |
| 124 | +# |
125 | 125 | $sfigSettings->datePickerDisabledDates = null; |
126 | 126 | |
127 | | -# # # |
| 127 | +## |
128 | 128 | # This is a string of highlighted dates. The days must be given as |
129 | 129 | # comma-separated list of dates or date ranges. The format for days is |
130 | 130 | # yyyy/mm/dd, for date ranges use yyyy/mm/dd-yyyy/mm/dd. Spaces are |
131 | 131 | # permissible. |
132 | 132 | # Sample value: "2010/12/25 - 2011/01/06, 2011/05/01" |
133 | | -# # |
| 133 | +# |
134 | 134 | $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 |
1 | 37 | + 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 |
2 | 38 | + 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 |
3 | 39 | + 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 |
4 | 40 | + 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 |
5 | 41 | + 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 |
6 | 42 | + 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 |
7 | 43 | + 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 |
8 | 44 | + 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 |
9 | 45 | + 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 |
10 | 46 | + 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 |
1 | 62 | + native |
Index: trunk/extensions/SemanticFormsInputs/SFI_Inputs.php |
— | — | @@ -5,7 +5,7 @@ |
6 | 6 | * @author Stephan Gambke |
7 | 7 | * @author Sanyam Goyal |
8 | 8 | * @author Yaron Koren |
9 | | - * @version 0.3.1 |
| 9 | + * @version 0.4 alpha |
10 | 10 | * |
11 | 11 | */ |
12 | 12 | |
— | — | @@ -16,89 +16,135 @@ |
17 | 17 | class SFIInputs { |
18 | 18 | |
19 | 19 | /** |
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. |
22 | 95 | */ |
23 | 96 | static private function regexpSetup() { |
24 | 97 | |
25 | 98 | global $wgOut; |
| 99 | + global $sfigSettings; |
26 | 100 | |
27 | 101 | static $hasRun = false; |
28 | 102 | |
29 | 103 | if ( !$hasRun ) { |
30 | 104 | $hasRun = true; |
31 | 105 | |
32 | | - wfLoadExtensionMessages( 'SemanticFormsInputs' ); |
| 106 | + $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->scriptPath . '/libs/regexp.js"></script> ' ); |
33 | 107 | |
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 | | - } |
67 | 108 | } |
68 | | -JAVASCRIPT; |
69 | | - |
70 | | - $wgOut->addInlineScript( $jstext ); |
71 | | - } |
72 | 109 | } |
73 | 110 | |
74 | 111 | |
75 | 112 | /** |
76 | 113 | * Definition of input type "regexp" |
77 | 114 | * |
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. |
81 | 118 | * |
| 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 |
82 | 127 | * @return array of two strings |
83 | 128 | */ |
84 | 129 | static function regexpHTML ( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
85 | 130 | |
86 | | - global $wgRequest, $wgUser, $wgParser; |
87 | | - global $sfgTabIndex; // used to represent the current tab index in the form |
| 131 | + global $wgOut; |
88 | 132 | global $sfgFieldNum; // used for setting various HTML IDs |
89 | 133 | global $sfgJSValidationCalls; // array of Javascript calls to determine if page can be saved |
90 | 134 | global $sfgFormPrinter; |
91 | 135 | |
92 | 136 | self::regexpSetup(); |
93 | 137 | |
94 | | - // set base type string |
| 138 | + // set base input type |
95 | 139 | if ( array_key_exists( 'base type', $other_args ) ) { |
| 140 | + |
96 | 141 | $baseType = trim( $other_args['base type'] ); |
97 | 142 | unset( $other_args['base type'] ); |
98 | | - } |
99 | | - else $baseType = null; |
100 | 143 | |
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 ) ) |
102 | 146 | $baseType = 'text'; |
| 147 | + } |
| 148 | + else $baseType = 'text'; |
103 | 149 | |
104 | 150 | // set base prefix string |
105 | 151 | if ( array_key_exists( 'base prefix', $other_args ) ) { |
— | — | @@ -127,7 +173,7 @@ |
128 | 174 | $regexp = str_replace( $orChar, '|', trim( $other_args['regexp'] ) ); |
129 | 175 | unset( $other_args['regexp'] ); |
130 | 176 | |
131 | | - // check for leading/trailing delimiter and remove it (else dump regexp) |
| 177 | + // check for leading/trailing delimiter and remove it (else reset regexp) |
132 | 178 | if ( preg_match ( "/^\/.*\/\$/", $regexp ) ) { |
133 | 179 | |
134 | 180 | $regexp = substr( $regexp, 1, strlen( $regexp ) - 2 ); |
— | — | @@ -145,6 +191,35 @@ |
146 | 192 | } |
147 | 193 | else $message = wfMsg( 'semanticformsinputs-wrongformat' ); |
148 | 194 | |
| 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 |
149 | 224 | $new_other_args = array(); |
150 | 225 | |
151 | 226 | foreach ( $other_args as $key => $value ) |
— | — | @@ -153,6 +228,7 @@ |
154 | 229 | } else |
155 | 230 | $new_other_args[$key] = $value; |
156 | 231 | |
| 232 | + // setup parameters for base input type |
157 | 233 | $funcArgs = array(); |
158 | 234 | $funcArgs[] = $cur_value; |
159 | 235 | $funcArgs[] = $input_name; |
— | — | @@ -160,31 +236,19 @@ |
161 | 237 | $funcArgs[] = $is_disabled; |
162 | 238 | $funcArgs[] = $new_other_args; |
163 | 239 | |
| 240 | + // get the input type hooks for the base input type |
164 | 241 | $hook_values = $sfgFormPrinter->mInputTypeHooks[$baseType]; |
165 | 242 | |
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 ); |
169 | 245 | |
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 | +} |
176 | 247 | |
177 | | - list( $htmltext, $jstext ) = call_user_func_array( $hook_values[0], $funcArgs ); |
178 | 248 | |
179 | | - $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' ); |
180 | | - |
181 | | - return array( $htmltext, "" ); |
182 | | - |
183 | | - } |
184 | | - |
185 | | - |
186 | 249 | /** |
187 | 250 | * 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. |
189 | 253 | */ |
190 | 254 | static private function jqDatePickerSetup () { |
191 | 255 | global $wgOut, $wgLang, $sfgScriptPath; |
— | — | @@ -198,6 +262,7 @@ |
199 | 263 | $wgOut->addScript( '<script type="text/javascript" src="' . $sfgScriptPath . '/libs/jquery-ui/jquery.ui.datepicker.min.js"></script> ' ); |
200 | 264 | $wgOut->addScript( '<script type="text/javascript" src="' . $sfigSettings->scriptPath . '/libs/datepicker.js"></script> ' ); |
201 | 265 | |
| 266 | + // set localized messages (use MW i18n, not jQuery i18n) |
202 | 267 | $jstext = |
203 | 268 | "jQuery(function($){\n" |
204 | 269 | . " $.datepicker.regional['wiki'] = {\n" |
— | — | @@ -271,15 +336,16 @@ |
272 | 337 | } |
273 | 338 | |
274 | 339 | /** |
275 | | - * expects a two dimensional array |
| 340 | + * Sort and merge time ranges in an array |
| 341 | + * |
| 342 | + * expects an array of arrays |
276 | 343 | * the inner arrays must contain two dates representing the start and end |
277 | 344 | * date of a time range |
278 | 345 | * |
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 |
281 | 348 | * |
282 | | - * |
283 | | - * @param array of arrays of DateTimes |
| 349 | + * @param array $ranges array of arrays of DateTimes |
284 | 350 | * @return array of arrays of DateTimes |
285 | 351 | */ |
286 | 352 | static private function sortAndMergeRanges ( $ranges ) { |
— | — | @@ -287,13 +353,18 @@ |
288 | 354 | // sort ranges, earliest date first |
289 | 355 | sort( $ranges ); |
290 | 356 | |
| 357 | + // stores the start of the current date range |
291 | 358 | $currmin = FALSE; |
| 359 | + |
| 360 | + // stores the date the next ranges start date has to top to not overlap |
292 | 361 | $nextmin = FALSE; |
293 | 362 | |
| 363 | + // result array |
294 | 364 | $mergedRanges = array(); |
295 | 365 | |
296 | 366 | foreach ( $ranges as $range ) { |
297 | 367 | |
| 368 | + // ignore empty date ranges |
298 | 369 | if ( !$range ) continue; |
299 | 370 | |
300 | 371 | if ( !$currmin ) { // found first valid range |
— | — | @@ -309,7 +380,7 @@ |
310 | 381 | $range[1]->modify( '+1 day' ); |
311 | 382 | $nextmin = max( $nextmin, $range[1] ); |
312 | 383 | |
313 | | - } else { // no overlap |
| 384 | + } else { // no overlap, store current range and continue with next |
314 | 385 | |
315 | 386 | $nextmin->modify( '-1 day' ); |
316 | 387 | $mergedRanges[] = array( $currmin, $nextmin ); |
— | — | @@ -333,55 +404,64 @@ |
334 | 405 | } |
335 | 406 | |
336 | 407 | /** |
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 |
338 | 411 | * "yyyy/mm/dd" or "yyyy/mm/dd-yyyy/mm/dd" |
339 | 412 | * |
340 | 413 | * returns an array of arrays, each of the latter consisting of two dates |
341 | 414 | * representing the start and end date of the range |
342 | 415 | * |
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 |
344 | 419 | * @return array of arrays of DateTimes |
345 | 420 | */ |
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 ) { |
352 | 422 | |
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', ' |
364 | 426 | |
| 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 | + |
365 | 439 | /** |
366 | 440 | * Takes an array of date ranges and returns an array containing the gaps |
367 | | - * between the ranges of the input array. |
368 | 441 | * |
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 |
370 | 447 | * @return array of arrays of DateTimes |
371 | 448 | */ |
372 | 449 | static private function invertRangesArray( $ranges ) { |
373 | 450 | |
| 451 | + // the result (initially empty) |
374 | 452 | $invRanges = null; |
| 453 | + |
| 454 | + // the minimum of the current gap (initially none) |
375 | 455 | $min = null; |
376 | 456 | |
377 | 457 | foreach ( $ranges as $range ) { |
378 | 458 | |
379 | | - if ( $min ) { |
| 459 | + if ( $min ) { // if min date of current gap is known store gap |
380 | 460 | $min->modify( "+1day " ); |
381 | 461 | $range[0]->modify( "-1day " ); |
382 | 462 | $invRanges[] = array( $min, $range[0] ); |
383 | 463 | } |
384 | 464 | |
385 | | - $min = $range[1]; |
| 465 | + $min = $range[1]; // store min date of next gap |
386 | 466 | |
387 | 467 | } |
388 | 468 | |
— | — | @@ -392,90 +472,89 @@ |
393 | 473 | /** |
394 | 474 | * Definition of input type "datepicker". |
395 | 475 | * |
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. |
399 | 480 | * |
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 |
401 | 487 | */ |
402 | 488 | static function jqDatePickerHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
403 | 489 | |
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 |
407 | 493 | |
408 | | - |
409 | 494 | // call common setup for all jqdatepickers |
410 | 495 | self::jqDatePickerSetup(); |
411 | 496 | |
| 497 | + // The datepicker is created in three steps: |
412 | 498 | // first: set up HTML attributes |
| 499 | + // second: set up JS attributes |
| 500 | + // third: assemble HTML and JS code |
413 | 501 | |
414 | | - // array of attributes to pass to the input field |
415 | | - $attribs = array( |
416 | | - "class" => "createboxInput", |
417 | | - "value" => $cur_value, |
418 | | - "type" => "text" |
419 | | - ); |
420 | 502 | |
| 503 | + // first: set up HTML attributes |
| 504 | + // nothing much to do here, self::textHTML will take care od the standard stuff |
421 | 505 | |
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 |
433 | 507 | if ( array_key_exists( 'class', $other_args ) ) { |
434 | | - $attribs["class"] .= ' ' . $other_args['class']; |
435 | 508 | $userClasses = $other_args['class']; |
436 | | - } |
| 509 | + } else $userClasses = ""; |
437 | 510 | |
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 ; |
442 | 516 | |
443 | | - $attribs["readonly"] = "1"; |
444 | | - |
445 | | - } |
446 | | - |
447 | 517 | // second: set up JS attributes, but only if we need them |
448 | 518 | if ( !$is_disabled ) { |
449 | 519 | |
450 | 520 | // find min date, max date and disabled dates |
451 | 521 | |
452 | 522 | // 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 | + } |
456 | 530 | |
457 | | - |
458 | | - |
459 | 531 | // 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 | + } |
463 | 539 | |
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 |
467 | 541 | if ( array_key_exists( 'possible_values', $other_args ) && count( $other_args['possible_values'] ) ) { |
468 | 542 | |
469 | 543 | $enabledDates = self::sortAndMergeRanges( self::createRangesArray( $other_args['possible_values'] ) ); |
470 | 544 | |
471 | 545 | // 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 | + } |
474 | 549 | |
| 550 | + if ( !$maxDate || $maxDate > $enabledDates[count( $enabledDates ) - 1][1] ) { |
| 551 | + $maxDate = $enabledDates[count( $enabledDates ) - 1][1]; |
| 552 | + } |
| 553 | + |
475 | 554 | $disabledDates = self::invertRangesArray( $enabledDates ); |
476 | 555 | |
477 | 556 | } else $disabledDates = array(); |
478 | 557 | |
479 | | - // add user-defined disabled values |
| 558 | + // add user-defined or default disabled values |
480 | 559 | if ( array_key_exists( 'disable dates', $other_args ) ) { |
481 | 560 | |
482 | 561 | $disabledDates = |
— | — | @@ -490,8 +569,10 @@ |
491 | 570 | |
492 | 571 | } |
493 | 572 | |
| 573 | + // if a minDate is set, discard all disabled dates below the min date |
494 | 574 | 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 |
496 | 577 | while ( $minDate && count( $disabledDates ) && $disabledDates[0][1] < $minDate ) array_shift( $disabledDates ); |
497 | 578 | |
498 | 579 | // if min date is in first disabled date range, discard that range and adjust min date |
— | — | @@ -502,8 +583,10 @@ |
503 | 584 | } |
504 | 585 | } |
505 | 586 | |
| 587 | + // if a maxDate is set, discard all disabled dates above the max date |
506 | 588 | 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 |
508 | 591 | while ( count( $disabledDates ) && $disabledDates[count( $disabledDates ) - 1][0] > $maxDate ) array_pop( $disabledDates ); |
509 | 592 | |
510 | 593 | // if max date is in last disabled date range, discard that range and adjust max date |
— | — | @@ -526,8 +609,11 @@ |
527 | 610 | |
528 | 611 | |
529 | 612 | // 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 | + } |
532 | 618 | |
533 | 619 | if ( $disabledDaysString != null ) { |
534 | 620 | |
— | — | @@ -546,10 +632,12 @@ |
547 | 633 | } |
548 | 634 | |
549 | 635 | // 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 | + } |
552 | 641 | |
553 | | - |
554 | 642 | if ( $highlightedDaysString != null ) { |
555 | 643 | |
556 | 644 | $highlightedDays = array( false, false, false, false, false, false, false ); |
— | — | @@ -561,6 +649,7 @@ |
562 | 650 | } |
563 | 651 | |
564 | 652 | } |
| 653 | + |
565 | 654 | } else { |
566 | 655 | $highlightedDays = null; |
567 | 656 | } |
— | — | @@ -568,11 +657,10 @@ |
569 | 658 | // set datepicker widget attributes |
570 | 659 | $jsattribs = array( |
571 | 660 | 'showOn' => 'both', |
572 | | - 'buttonImage' => $sfigSettings->scriptPath . '/DatePickerButton.gif', |
| 661 | + 'buttonImage' => $sfigSettings->scriptPath . '/images/DatePickerButton.gif', |
573 | 662 | 'buttonImageOnly' => false, |
574 | 663 | 'changeMonth' => true, |
575 | 664 | 'changeYear' => true, |
576 | | - 'altField' => "#input_{$sfgFieldNum}", |
577 | 665 | 'altFormat' => "yy/mm/dd", |
578 | 666 | // Today button does not work (http://dev.jqueryui.com/ticket/4045) |
579 | 667 | // do not show button panel for now |
— | — | @@ -581,9 +669,13 @@ |
582 | 670 | ); |
583 | 671 | |
584 | 672 | // 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 | + } |
588 | 680 | |
589 | 681 | // set show week number |
590 | 682 | if ( array_key_exists( 'show week numbers', $other_args ) |
— | — | @@ -594,19 +686,30 @@ |
595 | 687 | } |
596 | 688 | |
597 | 689 | // 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 |
598 | 693 | if ( $wgAmericanDates && $wgLang->getCode() == "en" ) { |
599 | 694 | |
600 | 695 | if ( array_key_exists( 'date format', $other_args ) ) { |
601 | 696 | |
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 | + } |
605 | 704 | |
606 | 705 | } elseif ( $sfigSettings->datePickerDateFormat ) { |
607 | 706 | |
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 | + } |
611 | 714 | |
612 | 715 | } else $jsattribs['dateFormat'] = 'yy/mm/dd'; |
613 | 716 | |
— | — | @@ -614,15 +717,23 @@ |
615 | 718 | |
616 | 719 | if ( array_key_exists( 'date format', $other_args ) ) { |
617 | 720 | |
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 | + } |
621 | 728 | |
622 | 729 | } elseif ( $sfigSettings->datePickerDateFormat ) { |
623 | 730 | |
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 | + } |
627 | 738 | |
628 | 739 | } else $jsattribs['dateFormat'] = 'yy/mm/dd'; |
629 | 740 | |
— | — | @@ -631,45 +742,49 @@ |
632 | 743 | } |
633 | 744 | |
634 | 745 | |
635 | | - // third: build HTML and JS code |
| 746 | + // third: assemble HTML and JS code |
636 | 747 | |
637 | | - |
638 | 748 | if ( $is_disabled ) { |
639 | 749 | |
640 | | - $attribs[ 'id' ] = "input_{$sfgFieldNum}"; |
641 | | - $attribs[ 'name' ] = $input_name; |
| 750 | + // if the input field is disabled, create a mockup without functionality |
642 | 751 | |
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", |
646 | 756 | array( |
647 | 757 | 'type' => 'button', |
648 | 758 | 'class' => $userClasses, |
649 | 759 | 'disabled' => '1', |
650 | 760 | 'id' => "input_{$sfgFieldNum}_button" |
651 | | - ), |
652 | | - Html::element( "image", |
653 | | - array( 'src' => $sfigSettings->scriptPath . '/DatePickerButtonDisabled.gif' ) |
| 761 | + ) ) |
654 | 762 | |
655 | | - ) |
656 | | - ); |
| 763 | + . Xml::element( "image", |
| 764 | + array( |
| 765 | + 'src' => $sfigSettings->scriptPath . '/images/DatePickerButtonDisabled.gif' |
| 766 | + ) ) |
657 | 767 | |
| 768 | + . Xml::closeElement( "button" ); |
| 769 | + |
658 | 770 | // append reset button if required |
659 | 771 | if ( array_key_exists( 'show reset button', $other_args ) || |
660 | 772 | $sfigSettings->datePickerShowResetButton && !array_key_exists( 'hide reset button', $other_args ) ) { |
661 | 773 | |
662 | | - $html .= Html::rawElement( "button", |
| 774 | + $html .= Xml::openElement( "button", |
663 | 775 | array( |
664 | 776 | 'type' => 'button', |
665 | 777 | 'class' => $userClasses, |
666 | 778 | 'disabled' => '1', |
667 | 779 | 'id' => "input_{$sfgFieldNum}_resetbutton" |
668 | | - ), |
669 | | - Html::element( "image", |
670 | | - array( 'src' => $sfigSettings->scriptPath . '/DatePickerResetButtonDisabled.gif' ) |
671 | | - ) |
672 | | - ); |
| 780 | + ) ) |
673 | 781 | |
| 782 | + . Xml::element( "image", |
| 783 | + array( |
| 784 | + 'src' => $sfigSettings->scriptPath . '/images/DatePickerResetButtonDisabled.gif' |
| 785 | + ) ) |
| 786 | + |
| 787 | + . Xml::closeElement( "button" ); |
| 788 | + |
674 | 789 | } |
675 | 790 | |
676 | 791 | // no JS needed on a disabled datepicker |
— | — | @@ -677,70 +792,78 @@ |
678 | 793 | |
679 | 794 | } else { |
680 | 795 | |
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" ) |
683 | 800 | |
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", |
689 | 802 | array( |
690 | 803 | "id" => "input_{$sfgFieldNum}", |
691 | 804 | "name" => $input_name, |
692 | 805 | "type" => "hidden" |
693 | | - ) |
694 | | - ); |
| 806 | + ) ); |
695 | 807 | |
696 | 808 | // append reset button if required |
697 | 809 | 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 ) ) { |
699 | 811 | |
| 812 | + // can not use Xml::element, it would sanitize the onclick attribute |
700 | 813 | $html .= "<button " |
701 | | - . Html::expandAttributes ( array( |
| 814 | + . Xml::expandAttributes ( array( |
702 | 815 | 'type' => 'button', |
703 | 816 | 'class' => $userClasses, |
704 | 817 | 'id' => "input_{$sfgFieldNum}_resetbutton", |
705 | 818 | ) ) |
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 | + . "\"" |
707 | 823 | . ">" |
708 | | - . Html::element( "image", array( 'src' => $sfigSettings->scriptPath . '/DatePickerResetButton.gif' ) ) |
709 | | - . "</button>"; |
710 | 824 | |
| 825 | + . Xml::element( "image", |
| 826 | + array( |
| 827 | + 'src' => $sfigSettings->scriptPath . '/images/DatePickerResetButton.gif' |
| 828 | + ) ) |
| 829 | + |
| 830 | + . Xml::closeElement( "button" ); |
| 831 | + |
711 | 832 | } |
712 | 833 | |
| 834 | + // sanitize current value before putting it into the JS code |
713 | 835 | $cur_value = Xml::escapeJsString( $cur_value ); |
714 | 836 | |
715 | | - |
716 | | - // build JS array |
| 837 | + // build JS code from attributes array |
717 | 838 | $jsattribsString = Xml::encodeJsVar( $jsattribs ); |
718 | 839 | |
719 | | - // attach datepicker to input field |
| 840 | + // assemble JS code to attach datepicker to input field |
720 | 841 | $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 | + }); |
725 | 848 | |
726 | 849 | JAVASCRIPT; |
727 | 850 | |
728 | | - // set first date |
| 851 | + // append setting of first date |
729 | 852 | if ( $minDate ) { |
730 | 853 | |
731 | 854 | $minDateString = $minDate->format( 'Y-m-d' ); |
732 | 855 | $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) ); |
734 | 857 | |
735 | 858 | JAVASCRIPT; |
736 | 859 | } |
737 | 860 | |
738 | | - // set last date |
| 861 | + // append setting of last date |
739 | 862 | if ( $maxDate ) { |
740 | 863 | |
741 | 864 | $maxDateString = $maxDate->format( 'Y-m-d' ); |
742 | 865 | |
743 | 866 | $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) ); |
745 | 868 | |
746 | 869 | JAVASCRIPT; |
747 | 870 | } |
— | — | @@ -749,85 +872,438 @@ |
750 | 873 | // add user-defined class(es) to all datepicker components |
751 | 874 | if ( array_key_exists( 'class', $other_args ) ) { |
752 | 875 | |
| 876 | + // sanitize names of user-defined classes |
753 | 877 | $userClasses = Xml::encodeJsVar ( $userClasses ); |
754 | 878 | |
755 | 879 | $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}); |
758 | 882 | |
759 | 883 | JAVASCRIPT; |
760 | | - |
761 | 884 | } |
762 | 885 | |
763 | | - // register disabled dates |
764 | | - // attach event handler to handle disabled dates |
| 886 | + // attach event handler to handle disabled and highlighted dates |
765 | 887 | if ( count( $disabledDates ) || count( $highlightedDates ) || count( $disabledDays ) || count( $highlightedDays ) ) { |
766 | 888 | |
767 | | - // register disabled dates with datepicker |
| 889 | + // first register disabled dates with datepicker |
768 | 890 | if ( count( $disabledDates ) ) { |
769 | 891 | |
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', ' |
771 | 894 | |
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" ); |
773 | 898 | |
| 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 | + |
774 | 909 | } |
775 | 910 | |
776 | | - // register highlighted dates with datepicker |
777 | | - if ( count( $highlightedDates ) ) { |
| 911 | + // then register highlighted dates with datepicker |
| 912 | + if ( count( $highlightedDates ) > 0 ) { |
778 | 913 | |
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', ' |
780 | 916 | |
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" ); |
782 | 920 | |
| 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 | + |
783 | 931 | } |
784 | 932 | |
785 | 933 | // register disabled days of week with datepicker |
786 | 934 | if ( count( $disabledDays ) ) { |
787 | 935 | $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"; |
789 | 937 | } |
790 | 938 | |
791 | 939 | // register highlighted days of week with datepicker |
792 | 940 | if ( count( $highlightedDays ) ) { |
793 | 941 | $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"; |
795 | 943 | } |
796 | 944 | |
| 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 |
797 | 948 | $jstext .= <<<JAVASCRIPT |
798 | 949 | |
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);}); |
800 | 951 | |
801 | 952 | JAVASCRIPT; |
802 | 953 | } |
803 | 954 | |
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 | + } |
808 | 960 | |
| 961 | + addOnloadHook(function(){initInput$sfgFieldNum("input_$sfgFieldNum");}); |
809 | 962 | JAVASCRIPT; |
810 | 963 | |
811 | 964 | |
812 | 965 | } |
813 | | - |
| 966 | + |
814 | 967 | // 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" ) ); |
816 | 969 | |
| 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 |
817 | 972 | $wgOut->addScript( '<script type="text/javascript">' . $jstext . '</script>' ); |
818 | 973 | |
819 | | - return array( $html, "" ); |
| 974 | + return array( $html, "", "initInput$sfgFieldNum" ); |
| 975 | + |
820 | 976 | } |
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 | +// |
826 | 1014 | |
827 | | - $y1 = $range[1]->format( "Y" ); |
828 | | - $m1 = $range[1]->format( "m" ) - 1; |
829 | | - $d1 = $range[1]->format( "d" ); |
830 | 1015 | |
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 | + |
832 | 1034 | } |
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 | + } |
834 | 1310 | } |
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 |
1 | 265 | + 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 |
1 | 58 | + 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 |
1 | 64 | + 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 |
1 | 156 | + native |
Index: trunk/extensions/SemanticFormsInputs/README |
— | — | @@ -16,15 +16,10 @@ |
17 | 17 | |
18 | 18 | == Installation == |
19 | 19 | |
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. |
24 | 23 | |
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 | | - |
29 | 24 | To install Semantic Forms Inputs, create a directory named |
30 | 25 | SemanticFormsInputs in the extensions directory of your MediaWiki |
31 | 26 | installation and copy the extension's files into it. Then add the |