Index: trunk/extensions/SemanticForms/includes/SF_TemplateField.inc |
— | — | @@ -1,195 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Defines a class, SFTemplateField, that represents a field in a template, |
5 | | - * including any possible semantic aspects it may have. Used in both creating |
6 | | - * templates and displaying user-created forms |
7 | | - * |
8 | | - * @author Yaron Koren |
9 | | - */ |
10 | | - |
11 | | -class SFTemplateField { |
12 | | - var $field_name; |
13 | | - var $value_labels; |
14 | | - var $label; |
15 | | - var $semantic_property; |
16 | | - var $field_type; |
17 | | - var $possible_values; |
18 | | - var $is_list; |
19 | | - var $input_type; |
20 | | - |
21 | | - static function create( $name, $label ) { |
22 | | - $f = new SFTemplateField(); |
23 | | - $f->field_name = trim( str_replace( '\\', '', $name ) ); |
24 | | - $f->label = trim( str_replace( '\\', '', $label ) ); |
25 | | - return $f; |
26 | | - } |
27 | | - |
28 | | - /** |
29 | | - * Create an SFTemplateField object based on the corresponding field |
30 | | - * in the template definition (which we first have to find) |
31 | | - */ |
32 | | - static function createFromList( $field_name, $all_fields, $strict_parsing ) { |
33 | | - // see if this field matches one of the fields defined for |
34 | | - // the template it's part of - if it is, use all available |
35 | | - // information about that field; if it's not, either create |
36 | | - // an object for it or not, depending on whether the |
37 | | - // template has a 'strict' setting in the form definition |
38 | | - $the_field = null; |
39 | | - foreach ( $all_fields as $cur_field ) { |
40 | | - if ( $field_name == $cur_field->field_name ) { |
41 | | - $the_field = $cur_field; |
42 | | - break; |
43 | | - } |
44 | | - } |
45 | | - if ( $the_field == null ) { |
46 | | - if ( $strict_parsing ) { |
47 | | - return null; |
48 | | - } |
49 | | - $the_field = new SFTemplateField(); |
50 | | - } |
51 | | - return $the_field; |
52 | | - } |
53 | | - |
54 | | - function setTypeAndPossibleValues() { |
55 | | - $proptitle = Title::makeTitleSafe( SMW_NS_PROPERTY, $this->semantic_property ); |
56 | | - if ( $proptitle === NULL ) |
57 | | - return; |
58 | | - $store = smwfGetStore(); |
59 | | - $types = $store->getPropertyValues( $proptitle, SMWPropertyValue::makeUserProperty( "Has type" ) ); |
60 | | - // this returns an array of objects |
61 | | - $allowed_values = $store->getPropertyValues( $proptitle, SMWPropertyValue::makeUserProperty( "Allows value" ) ); |
62 | | - $label_formats = $store->getPropertyValues( $proptitle, SMWPropertyValue::makeUserProperty( "Has field label format" ) ); |
63 | | - // TODO - need handling for the case of more than one type |
64 | | - if ( count( $types ) > 0 ) |
65 | | - $this->field_type = $types[0]->getWikiValue(); |
66 | | - |
67 | | - foreach ( $allowed_values as $value ) { |
68 | | - // HTML-unencode each value |
69 | | - $wiki_value = html_entity_decode( $value->getWikiValue() ); |
70 | | - $this->possible_values[] = $wiki_value; |
71 | | - if ( count( $label_formats ) > 0 ) { |
72 | | - $label_format = $label_formats[0]->getWikiValue(); |
73 | | - $prop_instance = SMWDataValueFactory::findTypeID( $this->field_type ); |
74 | | - $label_value = SMWDataValueFactory::newTypeIDValue( $prop_instance, $wiki_value ); |
75 | | - $label_value->setOutputFormat( $label_format ); |
76 | | - $this->value_labels[$wiki_value] = html_entity_decode( $label_value->getWikiValue() ); |
77 | | - } |
78 | | - } |
79 | | - |
80 | | - // HACK - if there were any possible values, set the field |
81 | | - // type to be 'enumeration', regardless of what the actual type is |
82 | | - if ( count( $this->possible_values ) > 0 ) { |
83 | | - $this->field_type = 'enumeration'; |
84 | | - } |
85 | | - } |
86 | | - |
87 | | - /** |
88 | | - * Called when template is parsed during the creation of a form |
89 | | - */ |
90 | | - function setSemanticProperty( $semantic_property ) { |
91 | | - $this->semantic_property = str_replace( '\\', '', $semantic_property ); |
92 | | - $this->possible_values = array(); |
93 | | - // set field type and possible values, if any |
94 | | - $this->setTypeAndPossibleValues(); |
95 | | - } |
96 | | - |
97 | | - /** |
98 | | - * Returns whether the semantic property represented by this field |
99 | | - * has the passed-in type constant (e.g., '_str', '_wpg') |
100 | | - */ |
101 | | - function propertyIsOfType( $type_constant ) { |
102 | | - global $smwgContLang; |
103 | | - $datatypeLabels = $smwgContLang->getDatatypeLabels(); |
104 | | - $page_type = $datatypeLabels[$type_constant]; |
105 | | - return ( $this->field_type == $page_type ); |
106 | | - } |
107 | | - |
108 | | - function createTemplateText( $template_name, $template_fields, $category, $aggregating_property, $aggregating_label, $template_format ) { |
109 | | - $template_header = wfMsgForContent( 'sf_template_docu', $template_name ); |
110 | | - $text = <<<END |
111 | | -<noinclude> |
112 | | -$template_header |
113 | | -<pre> |
114 | | - |
115 | | -END; |
116 | | - $text .= '{{' . $template_name; |
117 | | - if ( count( $template_fields ) > 0 ) { $text .= "\n"; } |
118 | | - foreach ( $template_fields as $field ) { |
119 | | - $text .= "|" . $field->field_name . "=\n"; |
120 | | - } |
121 | | - $template_footer = wfMsgForContent( 'sf_template_docufooter' ); |
122 | | - $text .= <<<END |
123 | | -}} |
124 | | -</pre> |
125 | | -$template_footer |
126 | | -</noinclude><includeonly> |
127 | | - |
128 | | -END; |
129 | | - // topmost part depends on format |
130 | | - if ( $template_format == 'infobox' ) { |
131 | | - // CSS style can't be used, unfortunately, since most MediaWiki |
132 | | - // setups don't have an 'infobox' or comparable CSS class |
133 | | - $text .= <<<END |
134 | | -{| style="width: 30em; font-size: 90%; border: 1px solid #aaaaaa; background-color: #f9f9f9; color: black; margin-bottom: 0.5em; margin-left: 1em; padding: 0.2em; float: right; clear: right; text-align:left;" |
135 | | -! style="text-align: center; background-color:#ccccff;" colspan="2" |<big>{{PAGENAME}}</big> |
136 | | -|- |
137 | | - |
138 | | -END; |
139 | | - } else { |
140 | | - $text .= '{| class="wikitable"' . "\n"; |
141 | | - } |
142 | | - |
143 | | - foreach ( $template_fields as $i => $field ) { |
144 | | - if ( $i > 0 ) { |
145 | | - $text .= "|-\n"; |
146 | | - } |
147 | | - $text .= "! " . $field->label . "\n"; |
148 | | - if ( $field->semantic_property == null || $field->semantic_property == '' ) { |
149 | | - $text .= "| {{{" . $field->field_name . "|}}}\n"; |
150 | | - // if this field is meant to contain a list, |
151 | | - // add on an 'arraymap' function, that will |
152 | | - // call this semantic markup tag on every |
153 | | - // element in the list |
154 | | - } elseif ( $field->is_list ) { |
155 | | - // find a string that's not in the semantic |
156 | | - // field call, to be used as the variable |
157 | | - $var = "x"; // default - use this if all the attempts fail |
158 | | - if ( strstr( $field->semantic_property, $var ) ) { |
159 | | - $var_options = array( 'y', 'z', 'xx', 'yy', 'zz', 'aa', 'bb', 'cc' ); |
160 | | - foreach ( $var_options as $option ) { |
161 | | - if ( ! strstr( $field->semantic_property, $option ) ) { |
162 | | - $var = $option; |
163 | | - break; |
164 | | - } |
165 | | - } |
166 | | - } |
167 | | - $text .= "| {{#arraymap:{{{" . $field->field_name . "|}}}|,|$var|[[" . $field->semantic_property . "::$var]]}}\n"; |
168 | | - } else { |
169 | | - $text .= "| [[" . $field->semantic_property . "::{{{" . $field->field_name . "|}}}]]\n"; |
170 | | - } |
171 | | - } |
172 | | - |
173 | | - // add a row with an inline query to this table, for aggregation, if |
174 | | - // a property was specified |
175 | | - if ( $aggregating_property != '' ) { |
176 | | - if ( count( $template_fields ) > 0 ) { |
177 | | - $text .= "|-\n"; |
178 | | - } |
179 | | - $text .= <<<END |
180 | | -! $aggregating_label |
181 | | -| {{#ask:[[$aggregating_property::{{SUBJECTPAGENAME}}]]|format=list}} |
182 | | - |
183 | | -END; |
184 | | - } |
185 | | - $text .= "|}\n"; |
186 | | - if ( $category != '' ) { |
187 | | - global $wgContLang; |
188 | | - $namespace_labels = $wgContLang->getNamespaces(); |
189 | | - $category_namespace = $namespace_labels[NS_CATEGORY]; |
190 | | - $text .= "\n[[$category_namespace:$category]]\n"; |
191 | | - } |
192 | | - $text .= "</includeonly>\n"; |
193 | | - |
194 | | - return $text; |
195 | | - } |
196 | | -} |
Index: trunk/extensions/SemanticForms/includes/SF_Utils.inc |
— | — | @@ -1,415 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Helper functions for the Semantic Forms extension. |
5 | | - * |
6 | | - * @author Yaron Koren |
7 | | - */ |
8 | | - |
9 | | -if ( !defined( 'MEDIAWIKI' ) ) die(); |
10 | | - |
11 | | -class SFUtils { |
12 | | - |
13 | | - static function initProperties() { |
14 | | - global $sfgContLang; |
15 | | - $sf_props = $sfgContLang->getPropertyLabels(); |
16 | | - if ( array_key_exists( SF_SP_HAS_DEFAULT_FORM, $sf_props ) ) |
17 | | - SMWPropertyValue::registerProperty( '_SF_DF', '__spf', $sf_props[SF_SP_HAS_DEFAULT_FORM], true ); |
18 | | - if ( array_key_exists( SF_SP_HAS_ALTERNATE_FORM, $sf_props ) ) |
19 | | - SMWPropertyValue::registerProperty( '_SF_AF', '__spf', $sf_props[SF_SP_HAS_ALTERNATE_FORM], true ); |
20 | | - if ( array_key_exists( SF_SP_CREATES_PAGES_WITH_FORM, $sf_props ) ) |
21 | | - SMWPropertyValue::registerProperty( '_SF_CP', '__spf', $sf_props[SF_SP_CREATES_PAGES_WITH_FORM], true ); |
22 | | - if ( array_key_exists( SF_SP_PAGE_HAS_DEFAULT_FORM, $sf_props ) ) |
23 | | - SMWPropertyValue::registerProperty( '_SF_PDF', '__spf', $sf_props[SF_SP_PAGE_HAS_DEFAULT_FORM], true ); |
24 | | - if ( array_key_exists( SF_SP_HAS_FIELD_LABEL_FORMAT, $sf_props ) ) |
25 | | - SMWPropertyValue::registerProperty( '_SF_FLF', '_str', $sf_props[SF_SP_HAS_FIELD_LABEL_FORMAT], true ); |
26 | | - // also initialize hardcoded English values, if it's a non-English-language wiki |
27 | | - SMWPropertyValue::registerProperty( '_SF_DF_BACKUP', '__spf', 'Has default form', true ); |
28 | | - SMWPropertyValue::registerProperty( '_SF_AF_BACKUP', '__spf', 'Has alternate form', true ); |
29 | | - SMWPropertyValue::registerProperty( '_SF_CP_BACKUP', '__spf', 'Creates pages with form', true ); |
30 | | - SMWPropertyValue::registerProperty( '_SF_PDF_BACKUP', '__spf', 'Page has default form', true ); |
31 | | - SMWPropertyValue::registerProperty( '_SF_FLF_BACKUP', '_str', 'Has field label format', true ); |
32 | | - |
33 | | - return true; |
34 | | - } |
35 | | - |
36 | | - /** |
37 | | - * Creates HTML linking to a wiki page |
38 | | - */ |
39 | | - static function linkText( $namespace, $name, $text = NULL ) { |
40 | | - global $wgContLang; |
41 | | - |
42 | | - $title = Title::makeTitleSafe( $namespace, $name ); |
43 | | - if ( $title === NULL ) { |
44 | | - return $name; // TODO maybe report an error here? |
45 | | - } |
46 | | - if ( NULL === $text ) $text = $title->getText(); |
47 | | - $l = new Linker(); |
48 | | - return $l->makeLinkObj( $title, $text ); |
49 | | - } |
50 | | - |
51 | | - /** |
52 | | - * Prints the mini-form contained at the bottom of various pages, that |
53 | | - * allows pages to spoof a normal edit page, that can preview, save, |
54 | | - * etc. |
55 | | - */ |
56 | | - static function printRedirectForm( $title, $page_contents, $edit_summary, $is_save, $is_preview, $is_diff, $is_minor_edit, $watch_this, $start_time, $edit_time ) { |
57 | | - if ( $title instanceof Title ) |
58 | | - $new_url = $title->getLocalURL( 'action=submit' ); |
59 | | - else |
60 | | - $new_url = $title; |
61 | | - global $wgUser; |
62 | | - if ( $wgUser->isLoggedIn() ) |
63 | | - $token = htmlspecialchars( $wgUser->editToken() ); |
64 | | - else |
65 | | - $token = EDIT_TOKEN_SUFFIX; |
66 | | - |
67 | | - $edit_summary = htmlspecialchars( $edit_summary ); |
68 | | - if ( $is_save ) |
69 | | - $action = "wpSave"; |
70 | | - elseif ( $is_preview ) |
71 | | - $action = "wpPreview"; |
72 | | - else // $is_diff |
73 | | - $action = "wpDiff"; |
74 | | - |
75 | | - global $sfgScriptPath; |
76 | | - $text = <<<END |
77 | | - <p style="position: absolute; left: 45%; top: 45%;"><img src="$sfgScriptPath/skins/loading.gif" /></p> |
78 | | - |
79 | | -END; |
80 | | - $form_body = ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpTextbox1', 'id' => 'wpTextbox1', 'value' => $page_contents ), null ) . "\n"; |
81 | | - $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpSummary', 'value' => $edit_summary ), null ) . "\n"; |
82 | | - $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpStarttime', 'value' => $start_time ), null ) . "\n"; |
83 | | - $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpEdittime', 'value' => $edit_time ), null ) . "\n"; |
84 | | - $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpEditToken', 'value' => $token ), null ) . "\n"; |
85 | | - $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => $action ), null ) . "\n"; |
86 | | - |
87 | | - if ( $is_minor_edit ) |
88 | | - $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpMinorEdit' ), null ) . "\n"; |
89 | | - if ( $watch_this ) |
90 | | - $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpWatchthis' ), null ) . "\n"; |
91 | | - $text .= Xml::tags( 'form', array( 'id' => 'editform', 'name' => 'editform', 'method' => 'post', 'action' => $new_url ), $form_body ); |
92 | | - |
93 | | - $text .= <<<END |
94 | | - <script type="text/javascript"> |
95 | | - window.onload = function() { |
96 | | - document.editform.submit(); |
97 | | - } |
98 | | - </script> |
99 | | - |
100 | | -END; |
101 | | - wfRunHooks( 'sfPrintRedirectForm', array( $is_save, $is_preview, $is_diff, &$text ) ); |
102 | | - return $text; |
103 | | - } |
104 | | - |
105 | | - /** |
106 | | - * Includes the necessary Javascript and CSS files for the form |
107 | | - * to display and work correctly |
108 | | - * |
109 | | - * Accepts an optional Parser instance, or uses $wgOut if omitted. |
110 | | - */ |
111 | | - static function addJavascriptAndCSS( $parser = NULL ) { |
112 | | - global $wgOut, $sfgScriptPath, $sfgYUIBase, $smwgScriptPath, $wgScriptPath, $wgFCKEditorDir, $wgJsMimeType, $sfgUseFormEditPage; |
113 | | - |
114 | | - $links = array( |
115 | | - array( |
116 | | - 'rel' => 'stylesheet', |
117 | | - 'type' => 'text/css', |
118 | | - 'media' => "screen", |
119 | | - 'href' => $sfgScriptPath . '/skins/SF_main.css' |
120 | | - ), |
121 | | - array( |
122 | | - 'rel' => 'stylesheet', |
123 | | - 'type' => 'text/css', |
124 | | - 'media' => "screen", |
125 | | - 'href' => $sfgYUIBase . "autocomplete/assets/skins/sam/autocomplete.css" |
126 | | - ), |
127 | | - array( |
128 | | - 'rel' => 'stylesheet', |
129 | | - 'type' => 'text/css', |
130 | | - 'media' => "screen", |
131 | | - 'href' => $sfgScriptPath . '/skins/SF_yui_autocompletion.css' |
132 | | - ), |
133 | | - array( |
134 | | - 'rel' => 'stylesheet', |
135 | | - 'type' => 'text/css', |
136 | | - 'media' => "screen", |
137 | | - 'href' => $sfgScriptPath . '/skins/floatbox.css' |
138 | | - ), |
139 | | - array( |
140 | | - 'rel' => 'stylesheet', |
141 | | - 'type' => 'text/css', |
142 | | - 'media' => "screen", |
143 | | - 'href' => $smwgScriptPath . '/skins/SMW_custom.css' |
144 | | - ), |
145 | | - ); |
146 | | - foreach ( $links as $link ) { |
147 | | - if ( $parser ) |
148 | | - $parser->getOutput()->addHeadItem( Xml::element( 'link', $link ) ); |
149 | | - else |
150 | | - $wgOut->addLink( $link ); |
151 | | - } |
152 | | - |
153 | | - |
154 | | - $scripts = array(); |
155 | | - $scripts[] = "{$sfgYUIBase}yahoo/yahoo-min.js"; |
156 | | - $scripts[] = "{$sfgYUIBase}dom/dom-min.js"; |
157 | | - $scripts[] = "{$sfgYUIBase}event/event-min.js"; |
158 | | - $scripts[] = "{$sfgYUIBase}get/get-min.js"; |
159 | | - $scripts[] = "{$sfgYUIBase}connection/connection-min.js"; |
160 | | - $scripts[] = "{$sfgYUIBase}json/json-min.js"; |
161 | | - $scripts[] = "{$sfgYUIBase}datasource/datasource-min.js"; |
162 | | - $scripts[] = "{$sfgYUIBase}autocomplete/autocomplete-min.js"; |
163 | | - $scripts[] = "$sfgScriptPath/libs/SF_yui_autocompletion.js"; |
164 | | - if ( !$sfgUseFormEditPage ) |
165 | | - $scripts[] = "$sfgScriptPath/libs/SF_ajax_form_preview.js"; |
166 | | - $scripts[] = "$sfgScriptPath/libs/floatbox.js"; |
167 | | - $scripts[] = "$smwgScriptPath/skins/SMW_tooltip.js"; |
168 | | - $scripts[] = "$smwgScriptPath/skins/SMW_sorttable.js"; |
169 | | - if ( $wgFCKEditorDir ) |
170 | | - $scripts[] = "$wgScriptPath/$wgFCKEditorDir/fckeditor.js"; |
171 | | - foreach ( $scripts as $js ) { |
172 | | - $script = "<script type=\"$wgJsMimeType\" src=\"$js\"></script>\n"; |
173 | | - if ( $parser ) |
174 | | - $parser->getOutput()->addHeadItem( $script ); |
175 | | - else |
176 | | - $wgOut->addScript( $script ); |
177 | | - } |
178 | | - if ( !$parser ) |
179 | | - $wgOut->addMeta( 'robots', 'noindex,nofollow' ); |
180 | | - } |
181 | | - |
182 | | - /** |
183 | | - * Return an array of all form names on this wiki |
184 | | - */ |
185 | | - static function getAllForms() { |
186 | | - $dbr = wfGetDB( DB_SLAVE ); |
187 | | - $query = "SELECT page_title FROM " . $dbr->tableName( 'page' ) . |
188 | | - " WHERE page_namespace = " . SF_NS_FORM . |
189 | | - " AND page_is_redirect = 0" . |
190 | | - " ORDER BY page_title"; |
191 | | - $res = $dbr->query( $query ); |
192 | | - $form_names = array(); |
193 | | - while ( $row = $dbr->fetchRow( $res ) ) { |
194 | | - $form_names[] = str_replace( '_', ' ', $row[0] ); |
195 | | - } |
196 | | - $dbr->freeResult( $res ); |
197 | | - return $form_names; |
198 | | - } |
199 | | - |
200 | | - static function formDropdownHTML() { |
201 | | - // create a dropdown of possible form names |
202 | | - global $sfgContLang; |
203 | | - $namespace_labels = $sfgContLang->getNamespaces(); |
204 | | - $form_label = $namespace_labels[SF_NS_FORM]; |
205 | | - $form_names = SFUtils::getAllForms(); |
206 | | - $select_body = ""; |
207 | | - foreach ( $form_names as $form_name ) { |
208 | | - $select_body .= ' ' . Xml::element( 'option', null, $form_name ) . "\n"; |
209 | | - } |
210 | | - $str = " $form_label:" . Xml::tags( 'select', array( 'name' => 'form' ), $select_body ) . "\n"; |
211 | | - return $str; |
212 | | - } |
213 | | - |
214 | | - /* |
215 | | - * This function, unlike the others, doesn't take in a substring |
216 | | - * because it uses the SMW data store, which can't perform |
217 | | - * case-insensitive queries; for queries with a substring, the |
218 | | - * function SFAutocompletAPI::getAllValuesForProperty() exists. |
219 | | - */ |
220 | | - static function getAllValuesForProperty( $property_name ) { |
221 | | - global $sfgMaxAutocompleteValues; |
222 | | - |
223 | | - $store = smwfGetStore(); |
224 | | - $requestoptions = new SMWRequestOptions(); |
225 | | - $requestoptions->limit = $sfgMaxAutocompleteValues; |
226 | | - $property = SMWPropertyValue::makeProperty( $property_name ); |
227 | | - $data_values = $store->getPropertyValues( null, $property, $requestoptions ); |
228 | | - $values = array(); |
229 | | - foreach ( $data_values as $dv ) { |
230 | | - // getPropertyValues() gets many repeat values - we want |
231 | | - // only one of each value |
232 | | - $string_value = str_replace( '_', ' ', $dv->getWikiValue() ); |
233 | | - if ( array_search( $string_value, $values ) === false ) |
234 | | - $values[] = $string_value; |
235 | | - } |
236 | | - return $values; |
237 | | - } |
238 | | - |
239 | | - /* |
240 | | - * Get all the pages that belong to a category and all its |
241 | | - * subcategories, down a certain number of levels - heavily based on |
242 | | - * SMW's SMWInlineQuery::includeSubcategories() |
243 | | - */ |
244 | | - static function getAllPagesForCategory( $top_category, $num_levels, $substring = null ) { |
245 | | - if ( 0 == $num_levels ) return $top_category; |
246 | | - global $sfgMaxAutocompleteValues; |
247 | | - |
248 | | - $db = wfGetDB( DB_SLAVE ); |
249 | | - $top_category = str_replace( ' ', '_', $top_category ); |
250 | | - $categories = array( $top_category ); |
251 | | - $checkcategories = array( $top_category ); |
252 | | - $pages = array(); |
253 | | - for ( $level = $num_levels; $level > 0; $level-- ) { |
254 | | - $newcategories = array(); |
255 | | - foreach ( $checkcategories as $category ) { |
256 | | - if ( $substring != null ) { |
257 | | - $substring = str_replace( ' ', '_', strtolower( $substring ) ); |
258 | | - $substring = str_replace( '_', '\_', $substring ); |
259 | | - $substring = str_replace( "'", "\'", $substring ); |
260 | | - $conditions = 'cl_to = ' . $db->addQuotes( $category ) . " AND (LOWER(CONVERT(`page_title` USING utf8)) LIKE '" . $substring . "%' OR LOWER(CONVERT(`page_title` USING utf8)) LIKE '%\_" . $substring . "%' OR page_namespace = " . NS_CATEGORY . ")"; |
261 | | - } else { |
262 | | - $conditions = 'cl_to = ' . $db->addQuotes( $category ); |
263 | | - } |
264 | | - $res = $db->select( // make the query |
265 | | - array( 'categorylinks', 'page' ), |
266 | | - array( 'page_title', 'page_namespace' ), |
267 | | - array( 'cl_from = page_id', $conditions ), |
268 | | - __METHOD__, |
269 | | - 'SORT BY cl_sortkey' ); |
270 | | - if ( $res ) { |
271 | | - while ( $res && $row = $db->fetchRow( $res ) ) { |
272 | | - if ( array_key_exists( 'page_title', $row ) ) { |
273 | | - $page_namespace = $row['page_namespace']; |
274 | | - if ( $page_namespace == NS_CATEGORY ) { |
275 | | - $new_category = $row[ 'page_title' ]; |
276 | | - if ( !in_array( $new_category, $categories ) ) { |
277 | | - $newcategories[] = $new_category; |
278 | | - } |
279 | | - } else { |
280 | | - $cur_value = str_replace( "_", " ", $row['page_title'] ); |
281 | | - if ( ! in_array( $cur_value, $pages ) ) { |
282 | | - if ( $substring == null ) |
283 | | - $pages[] = $cur_value; |
284 | | - else |
285 | | - $pages[] = array( 'title' => $cur_value ); |
286 | | - } |
287 | | - // return if we've reached the maximum number of allowed values |
288 | | - if ( count( $pages ) > $sfgMaxAutocompleteValues ) |
289 | | - return $pages; |
290 | | - } |
291 | | - } |
292 | | - } |
293 | | - $db->freeResult( $res ); |
294 | | - } |
295 | | - } |
296 | | - if ( count( $newcategories ) == 0 ) { |
297 | | - return $pages; |
298 | | - } else { |
299 | | - $categories = array_merge( $categories, $newcategories ); |
300 | | - } |
301 | | - $checkcategories = array_diff( $newcategories, array() ); |
302 | | - } |
303 | | - return $pages; |
304 | | - } |
305 | | - |
306 | | - static function getAllPagesForConcept( $concept_name, $substring = null ) { |
307 | | - global $sfgMaxAutocompleteValues; |
308 | | - |
309 | | - // TODO - substring isn't being handled. Is there a way to |
310 | | - // include it through the API? |
311 | | - $store = smwfGetStore(); |
312 | | -/* |
313 | | - $requestoptions = new SMWRequestOptions(); |
314 | | - if ($substring != null) { |
315 | | - $requestoptions->addStringCondition($substring, SMWStringCondition::STRCOND_PRE); |
316 | | - } |
317 | | -*/ |
318 | | - $concept = Title::makeTitleSafe( SMW_NS_CONCEPT, $concept_name ); |
319 | | - // escape if there's a problem |
320 | | - if ( $concept == null ) |
321 | | - return array(); |
322 | | - $desc = new SMWConceptDescription( $concept ); |
323 | | - $printout = new SMWPrintRequest( SMWPrintRequest::PRINT_THIS, "" ); |
324 | | - $desc->addPrintRequest( $printout ); |
325 | | - $query = new SMWQuery( $desc ); |
326 | | - $query->setLimit( $sfgMaxAutocompleteValues ); |
327 | | - $query_result = $store->getQueryResult( $query ); |
328 | | - $pages = array(); |
329 | | - while ( $res = $query_result->getNext() ) { |
330 | | - $pages[] = $res[0]->getNextText( SMW_OUTPUT_WIKI ); |
331 | | - } |
332 | | - sort( $pages ); |
333 | | - return $pages; |
334 | | - } |
335 | | - |
336 | | - static function getAllPagesForNamespace( $namespace_name, $substring = null ) { |
337 | | - // cycle through all the namespace names for this language, and |
338 | | - // if one matches the namespace specified in the form, add the |
339 | | - // names of all the pages in that namespace to $names_array |
340 | | - global $wgContLang; |
341 | | - $namespaces = $wgContLang->getNamespaces(); |
342 | | - $db = wfGetDB( DB_SLAVE ); |
343 | | - $pages = array(); |
344 | | - foreach ( $namespaces as $ns_code => $ns_name ) { |
345 | | - if ( $ns_name == $namespace_name ) { |
346 | | - $conditions = "page_namespace = $ns_code"; |
347 | | - if ( $substring != null ) { |
348 | | - $substring = str_replace( ' ', '_', strtolower( $substring ) ); |
349 | | - $substring = str_replace( '_', '\_', $substring ); |
350 | | - $substring = str_replace( "'", "\'", $substring ); |
351 | | - $conditions .= " AND (LOWER(CONVERT(`page_title` USING utf8)) LIKE '$substring%' OR LOWER(CONVERT(`page_title` USING utf8)) LIKE '%\_$substring%')"; |
352 | | - } |
353 | | - $sql_options['ORDER BY'] = 'page_title'; |
354 | | - $res = $db->select( $db->tableNames( 'page' ), |
355 | | - 'page_title', |
356 | | - $conditions, __METHOD__, $sql_options ); |
357 | | - while ( $row = $db->fetchRow( $res ) ) { |
358 | | - $cur_value = str_replace( '_', ' ', $row[0] ); |
359 | | - if ( $substring == null ) { |
360 | | - $pages[] = $cur_value; |
361 | | - } else { |
362 | | - $pages[] = array( 'title' => $cur_value ); |
363 | | - } |
364 | | - } |
365 | | - $db->freeResult( $res ); |
366 | | - } |
367 | | - } |
368 | | - return $pages; |
369 | | - } |
370 | | - |
371 | | - static function getValuesFromExternalURL( $external_url_alias, $substring ) { |
372 | | - global $sfgAutocompletionURLs; |
373 | | - if ( empty( $sfgAutocompletionURLs ) ) return array(); |
374 | | - $url = $sfgAutocompletionURLs[$external_url_alias]; |
375 | | - if ( empty( $url ) ) return array(); |
376 | | - $url = str_replace( '<substr>', $substring, $url ); |
377 | | - $page_contents = Http::get( $url ); |
378 | | - if ( empty( $page_contents ) ) return array(); |
379 | | - $data = json_decode( $page_contents ); |
380 | | - if ( empty( $data ) ) return array(); |
381 | | - $return_values = array(); |
382 | | - foreach ( $data->sfautocomplete as $val ) { |
383 | | - $return_values[] = (array)$val; |
384 | | - } |
385 | | - return $return_values; |
386 | | - } |
387 | | - |
388 | | - /** |
389 | | - * Parse the form definition and store the resulting HTML in the |
390 | | - * page_props table, if caching has been specified in LocalSettings.php |
391 | | - */ |
392 | | - function cacheFormDefinition( $parser, $text ) { |
393 | | - global $sfgCacheFormDefinitions; |
394 | | - if ( ! $sfgCacheFormDefinitions ) |
395 | | - return true; |
396 | | - |
397 | | - $title = $parser->getTitle(); |
398 | | - if ( empty( $title ) ) return true; |
399 | | - if ( $title->getNamespace() != SF_NS_FORM ) return true; |
400 | | - // Remove <noinclude> sections and <includeonly> tags from form definition |
401 | | - $form_def = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $text ); |
402 | | - $form_def = strtr( $form_def, array( '<includeonly>' => '', '</includeonly>' => '' ) ); |
403 | | - |
404 | | - // parse wiki-text |
405 | | - // add '<nowiki>' tags around every triple-bracketed form |
406 | | - // definition element, so that the wiki parser won't touch |
407 | | - // it - the parser will remove the '<nowiki>' tags, leaving |
408 | | - // us with what we need |
409 | | - $form_def = "__NOEDITSECTION__" . strtr( $form_def, array( '{{{' => '<nowiki>{{{', '}}}' => '}}}</nowiki>' ) ); |
410 | | - $dummy_title = Title::newFromText( 'Form definition title for caching purposes' ); |
411 | | - $form_def = $parser->parse( $form_def, $dummy_title, $parser->mOptions )->getText(); |
412 | | - |
413 | | - $parser->mOutput->setProperty( 'formdefinition', $form_def ); |
414 | | - return true; |
415 | | - } |
416 | | -} |
Index: trunk/extensions/SemanticForms/includes/SF_FormClasses.inc |
— | — | @@ -1,212 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Two classes - SFForm and SFTemplateInForm - that represent a user-defined |
5 | | - * form and a template contained within that form, respectively. |
6 | | - * |
7 | | - * @author Yaron Koren |
8 | | - */ |
9 | | - |
10 | | -class SFForm { |
11 | | - var $form_name; |
12 | | - var $templates; |
13 | | - |
14 | | - static function create( $form_name, $templates ) { |
15 | | - $form = new SFForm(); |
16 | | - $form->form_name = ucfirst( str_replace( '_', ' ', $form_name ) ); |
17 | | - $form->templates = $templates; |
18 | | - return $form; |
19 | | - } |
20 | | - |
21 | | - function creationHTML() { |
22 | | - $text = ""; |
23 | | - foreach ( $this->templates as $i => $ft ) { |
24 | | - $text .= $ft->creationHTML( $i ); |
25 | | - } |
26 | | - return $text; |
27 | | - } |
28 | | - |
29 | | - function createMarkup() { |
30 | | - $title = Title::makeTitle( SF_NS_FORM, $this->form_name ); |
31 | | - $fs = SpecialPage::getPage( 'FormStart' ); |
32 | | - $form_start_url = SFLinkUtils::titleURLString( $fs->getTitle() ) . "/" . $title->getPartialURL(); |
33 | | - $form_description = wfMsgForContent( 'sf_form_docu', $this->form_name, $form_start_url ); |
34 | | - $form_input = "{{#forminput:form=" . $this->form_name . "}}\n"; |
35 | | - $text = <<<END |
36 | | -<noinclude> |
37 | | -$form_description |
38 | | - |
39 | | - |
40 | | -$form_input |
41 | | -</noinclude><includeonly> |
42 | | -<div id="wikiPreview" style="display: none; padding-bottom: 25px; margin-bottom: 25px; border-bottom: 1px solid #AAAAAA;"></div> |
43 | | - |
44 | | -END; |
45 | | - foreach ( $this->templates as $template ) { |
46 | | - $text .= $template->createMarkup() . "\n"; |
47 | | - } |
48 | | - $free_text_label = wfMsgForContent( 'sf_form_freetextlabel' ); |
49 | | - $text .= <<<END |
50 | | -'''$free_text_label:''' |
51 | | - |
52 | | -{{{standard input|free text|rows=10}}} |
53 | | - |
54 | | - |
55 | | -{{{standard input|summary}}} |
56 | | - |
57 | | -{{{standard input|minor edit}}} {{{standard input|watch}}} |
58 | | - |
59 | | -{{{standard input|save}}} {{{standard input|preview}}} {{{standard input|changes}}} {{{standard input|cancel}}} |
60 | | -</includeonly> |
61 | | - |
62 | | -END; |
63 | | - |
64 | | - return $text; |
65 | | - } |
66 | | - |
67 | | -} |
68 | | - |
69 | | -class SFTemplateInForm { |
70 | | - var $template_name; |
71 | | - var $label; |
72 | | - var $allow_multiple; |
73 | | - var $max_allowed; |
74 | | - var $fields; |
75 | | - |
76 | | - function getAllFields() { |
77 | | - global $wgContLang; |
78 | | - $template_fields = array(); |
79 | | - $field_names_array = array(); |
80 | | - |
81 | | - // Get the fields of the template, both semantic and otherwise, by parsing |
82 | | - // the text of the template. |
83 | | - // The way this works is that fields are found and then stored in an |
84 | | - // array based on their location in the template text, so that they |
85 | | - // can be returned in the order in which they appear in the template, even |
86 | | - // though they were found in a different order. |
87 | | - // Some fields can be found more than once (especially if they're part |
88 | | - // of an "#if" statement), so they're only recorded the first time they're |
89 | | - // found. Also, every field gets replaced with a string of x's after |
90 | | - // being found, so it doesn't interfere with future parsing. |
91 | | - $template_title = Title::makeTitleSafe( NS_TEMPLATE, $this->template_name ); |
92 | | - $template_article = null; |
93 | | - if ( isset( $template_title ) ) $template_article = new Article( $template_title ); |
94 | | - if ( isset( $template_article ) ) { |
95 | | - $template_text = $template_article->getContent(); |
96 | | - // ignore 'noinclude' sections and 'includeonly' tags |
97 | | - $template_text = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $template_text ); |
98 | | - $template_text = strtr( $template_text, array( '<includeonly>' => '', '</includeonly>' => '' ) ); |
99 | | - |
100 | | - // first, look for "arraymap" parser function calls that map a |
101 | | - // property onto a list |
102 | | - if ( preg_match_all( '/{{#arraymap:{{{([^|}]*:?[^|}]*)[^\[]*\[\[([^:=]*:?[^:=]*)(:[:=])/mis', $template_text, $matches ) ) { |
103 | | - // this is a two-dimensional array; we need the last three of the four |
104 | | - // sub-arrays; we also have to remove redundant values |
105 | | - foreach ( $matches[1] as $i => $field_name ) { |
106 | | - $semantic_property = $matches[2][$i]; |
107 | | - $full_field_text = $matches[0][$i]; |
108 | | - if ( ! in_array( $field_name, $field_names_array ) ) { |
109 | | - $template_field = SFTemplateField::create( $field_name, $wgContLang->ucfirst( $field_name ) ); |
110 | | - $template_field->setSemanticProperty( $semantic_property ); |
111 | | - $template_field->is_list = true; |
112 | | - $cur_pos = stripos( $template_text, $full_field_text ); |
113 | | - $template_fields[$cur_pos] = $template_field; |
114 | | - $field_names_array[] = $field_name; |
115 | | - $replacement = str_repeat( "x", strlen( $full_field_text ) ); |
116 | | - $template_text = str_replace( $full_field_text, $replacement, $template_text ); |
117 | | - } |
118 | | - } |
119 | | - } |
120 | | - |
121 | | - // second, look for normal property calls |
122 | | - if ( preg_match_all( '/\[\[([^:=]*:*?[^:=]*)(:[:=]){{{([^\]\|}]*).*?\]\]/mis', $template_text, $matches ) ) { |
123 | | - // this is a two-dimensional array; we need the last three of the four |
124 | | - // sub-arrays; we also have to remove redundant values |
125 | | - foreach ( $matches[1] as $i => $semantic_property ) { |
126 | | - $field_name = $matches[3][$i]; |
127 | | - $full_field_text = $matches[0][$i]; |
128 | | - if ( ! in_array( $field_name, $field_names_array ) ) { |
129 | | - $template_field = SFTemplateField::create( $field_name, $wgContLang->ucfirst( $field_name ) ); |
130 | | - $template_field->setSemanticProperty( $semantic_property ); |
131 | | - $cur_pos = stripos( $template_text, $full_field_text ); |
132 | | - $template_fields[$cur_pos] = $template_field; |
133 | | - $field_names_array[] = $field_name; |
134 | | - $replacement = str_repeat( "x", strlen( $full_field_text ) ); |
135 | | - $template_text = str_replace( $full_field_text, $replacement, $template_text ); |
136 | | - } |
137 | | - } |
138 | | - } |
139 | | - |
140 | | - // finally, get any non-semantic fields defined |
141 | | - if ( preg_match_all( '/{{{([^|}]*)/mis', $template_text, $matches ) ) { |
142 | | - foreach ( $matches[1] as $i => $field_name ) { |
143 | | - $full_field_text = $matches[0][$i]; |
144 | | - if ( ( $full_field_text != '' ) && ( ! in_array( $field_name, $field_names_array ) ) ) { |
145 | | - $cur_pos = stripos( $template_text, $full_field_text ); |
146 | | - $template_fields[$cur_pos] = SFTemplateField::create( $field_name, $wgContLang->ucfirst( $field_name ) ); |
147 | | - $field_names_array[] = $field_name; |
148 | | - } |
149 | | - } |
150 | | - } |
151 | | - } |
152 | | - ksort( $template_fields ); |
153 | | - return $template_fields; |
154 | | - } |
155 | | - |
156 | | - static function create( $name, $label, $allow_multiple, $max_allowed = null ) { |
157 | | - $tif = new SFTemplateInForm(); |
158 | | - $tif->template_name = str_replace( '_', ' ', $name ); |
159 | | - $tif->fields = array(); |
160 | | - $fields = $tif->getAllFields(); |
161 | | - $field_num = 0; |
162 | | - foreach ( $fields as $field ) { |
163 | | - $tif->fields[] = SFFormField::create( $field_num++, $field ); |
164 | | - } |
165 | | - $tif->label = $label; |
166 | | - $tif->allow_multiple = $allow_multiple; |
167 | | - $tif->max_allowed = $max_allowed; |
168 | | - return $tif; |
169 | | - } |
170 | | - |
171 | | - function creationHTML( $template_num ) { |
172 | | - $checked_str = ( $this->allow_multiple ) ? "checked" : ""; |
173 | | - $template_str = wfMsg( 'sf_createform_template' ); |
174 | | - $template_label_input = wfMsg( 'sf_createform_templatelabelinput' ); |
175 | | - $allow_multiple_text = wfMsg( 'sf_createform_allowmultiple' ); |
176 | | - $text = <<<END |
177 | | - <input type="hidden" name="template_$template_num" value="$this->template_name"> |
178 | | - <div class="templateForm"> |
179 | | - <h2>$template_str '$this->template_name'</h2> |
180 | | - <p>$template_label_input <input size=25 name="label_$template_num" value="$this->label"></p> |
181 | | - <p><input type="checkbox" name="allow_multiple_$template_num" $checked_str> $allow_multiple_text</p> |
182 | | - <hr> |
183 | | - |
184 | | -END; |
185 | | - foreach ( $this->fields as $field ) { |
186 | | - $text .= $field->creationHTML( $template_num ); |
187 | | - } |
188 | | - $text .= ' <p><input type="submit" name="del_' . $template_num . |
189 | | - '" value="' . wfMsg( 'sf_createform_removetemplate' ) . '"></p>' . "\n"; |
190 | | - $text .= " </div>\n"; |
191 | | - return $text; |
192 | | - } |
193 | | - |
194 | | - function createMarkup() { |
195 | | - $text = ""; |
196 | | - $text .= "{{{for template|" . $this->template_name; |
197 | | - if ( $this->allow_multiple ) |
198 | | - $text .= "|multiple"; |
199 | | - if ( $this->label != '' ) |
200 | | - $text .= "|label=" . $this->label; |
201 | | - $text .= "}}}\n"; |
202 | | - // for now, HTML for templates differs for multiple-instance templates; |
203 | | - // this may change if handling of form definitions gets more sophisticated |
204 | | - if ( ! $this->allow_multiple ) { $text .= "{| class=\"formtable\"\n"; } |
205 | | - foreach ( $this->fields as $i => $field ) { |
206 | | - $is_last_field = ( $i == count( $this->fields ) - 1 ); |
207 | | - $text .= $field->createMarkup( $this->allow_multiple, $is_last_field ); |
208 | | - } |
209 | | - if ( ! $this->allow_multiple ) { $text .= "|}\n"; } |
210 | | - $text .= "{{{end template}}}\n"; |
211 | | - return $text; |
212 | | - } |
213 | | -} |
Index: trunk/extensions/SemanticForms/includes/SF_FormUtils.inc |
— | — | @@ -1,1108 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Javascript- and HTML-creation utilities for the display of a form |
5 | | - * |
6 | | - * @author Yaron Koren |
7 | | - * @author Jeffrey Stuckman |
8 | | - * @author Harold Solbrig |
9 | | - * @author Eugene Mednikov |
10 | | - */ |
11 | | - |
12 | | -class SFFormUtils { |
13 | | - |
14 | | - static function chooserJavascript() { |
15 | | - $javascript_text = <<<END |
16 | | -<script type="text/javascript">/* <![CDATA[ */ |
17 | | - |
18 | | -function updatechooserbutton(f,n) |
19 | | -{ |
20 | | - document.getElementById(n).disabled = (f.options[f.selectedIndex].value=="invalid"); |
21 | | -} |
22 | | - |
23 | | -function addInstanceFromChooser(chooserid) |
24 | | -{ |
25 | | - var chooser = document.getElementById(chooserid); |
26 | | - var optionstring = chooser.options[chooser.selectedIndex].value; |
27 | | - var pos = optionstring.indexOf(","); |
28 | | - var tabindex = optionstring.substr(0,pos); |
29 | | - var chooservalue = optionstring.substr(pos+1); |
30 | | - addInstance('starter_' + chooservalue, 'main_' + chooservalue, parseInt(tabindex)); |
31 | | -} |
32 | | - |
33 | | -//The fieldset containing the given element was just updated. If the fieldset is associated with a chooser, |
34 | | -//ensure that the fieldset is hidden if and only if there are no template instances inside. |
35 | | -function hideOrShowFieldset(element) |
36 | | -{ |
37 | | - //Find fieldset |
38 | | - while (element.tagName.toLowerCase() != "fieldset") |
39 | | - element = element.parentNode; |
40 | | - //Bail out if fieldset is not part of chooser |
41 | | - if (!element.getAttribute("haschooser")) |
42 | | - return; |
43 | | - //Now look for "input" or "select" tags that don't look like they're part of the starter template |
44 | | - var inputs = element.getElementsByTagName("input"); |
45 | | - var x; |
46 | | - var show = false; |
47 | | - for (x=0;x<inputs.length;x++) |
48 | | - { |
49 | | - if (inputs[x].type=="text" && inputs[x].name.indexOf("[num]") == -1) |
50 | | - show = true; |
51 | | - } |
52 | | - var selects = element.getElementsByTagName("select"); |
53 | | - for (x=0;x<selects.length;x++) |
54 | | - { |
55 | | - if (selects[x].name.indexOf("[num]") == -1) |
56 | | - show = true; |
57 | | - } |
58 | | - //Now show or hide fieldset |
59 | | - element.style.display = (show?"block":"none"); |
60 | | -} |
61 | | -/* ]]> */ </script> |
62 | | - |
63 | | -END; |
64 | | - return $javascript_text; |
65 | | - } |
66 | | - |
67 | | - /** |
68 | | - * All the Javascript calls to validate both the type of each |
69 | | - * form field and their presence, for mandatory fields |
70 | | - */ |
71 | | - static function validationJavascript() { |
72 | | - global $sfgJSValidationCalls; |
73 | | - |
74 | | - $form_errors_header = Xml::escapeJsString( wfMsg( 'sf_formerrors_header' ) ); |
75 | | - $blank_error_str = Xml::escapeJsString( wfMsg( 'sf_blank_error' ) ); |
76 | | - $bad_url_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_url_error' ) ); |
77 | | - $bad_email_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_email_error' ) ); |
78 | | - $bad_number_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_number_error' ) ); |
79 | | - $bad_integer_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_integer_error' ) ); |
80 | | - $bad_date_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_date_error' ) ); |
81 | | - |
82 | | - $javascript_text = <<<END |
83 | | - |
84 | | -function validate_mandatory_field(field_id, info_id) { |
85 | | - field = document.getElementById(field_id); |
86 | | - if (field.value.replace(/\s+/, '') == '') { |
87 | | - infobox = document.getElementById(info_id); |
88 | | - infobox.innerHTML = "$blank_error_str"; |
89 | | - return false; |
90 | | - } else { |
91 | | - return true; |
92 | | - } |
93 | | -} |
94 | | - |
95 | | -// special handling for radiobuttons, because what's being checked |
96 | | -// is the first radiobutton, which has value of "None" |
97 | | -function validate_mandatory_radiobutton(none_button_id, info_id) { |
98 | | - none_button = document.getElementById(none_button_id); |
99 | | - if (none_button && none_button.checked) { |
100 | | - infobox = document.getElementById(info_id); |
101 | | - infobox.innerHTML = "$blank_error_str"; |
102 | | - return false; |
103 | | - } else { |
104 | | - return true; |
105 | | - } |
106 | | -} |
107 | | - |
108 | | -function validate_mandatory_checkboxes(field_id, info_id) { |
109 | | - elems = document.getElementsByTagName("*"); |
110 | | - var all_fields_unchecked = true; |
111 | | - for (var i = 0; i < elems.length; i++) { |
112 | | - if (elems[i].id == field_id) { |
113 | | - if (elems[i].checked) { |
114 | | - all_fields_unchecked = false; |
115 | | - } |
116 | | - } |
117 | | - } |
118 | | - if (all_fields_unchecked) { |
119 | | - infobox = document.getElementById(info_id); |
120 | | - infobox.innerHTML = "$blank_error_str"; |
121 | | - return false; |
122 | | - } else { |
123 | | - return true; |
124 | | - } |
125 | | -} |
126 | | - |
127 | | -// validate a mandatory field that exists across multiple instances of |
128 | | -// a template - we have to find each one, matching on the pattern of its |
129 | | -// ID, and validate it |
130 | | -function validate_multiple_mandatory_fields(field_num) { |
131 | | - var num_errors = 0; |
132 | | - elems = document.getElementsByTagName("*"); |
133 | | - var field_pattern = new RegExp('input_(.*)_' + field_num); |
134 | | - for (var i = 0; i < elems.length; i++) { |
135 | | - id = elems[i].id; |
136 | | - if (matches = field_pattern.exec(id)) { |
137 | | - instance_num = matches[1]; |
138 | | - var input_name = "input_" + instance_num + "_" + field_num; |
139 | | - var info_name = "info_" + instance_num + "_" + field_num; |
140 | | - if (! validate_mandatory_field(input_name, info_name)) { |
141 | | - num_errors += 1; |
142 | | - } |
143 | | - } |
144 | | - } |
145 | | - return (num_errors == 0); |
146 | | -} |
147 | | - |
148 | | -function validate_field_type(field_id, type, info_id) { |
149 | | - field = document.getElementById(field_id); |
150 | | - if (type != 'date' && field.value == '') { |
151 | | - return true; |
152 | | - } else { |
153 | | - if (type == 'URL') { |
154 | | - // code borrowed from http://snippets.dzone.com/posts/show/452 |
155 | | - var url_regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; |
156 | | - if (url_regexp.test(field.value)) { |
157 | | - return true; |
158 | | - } else { |
159 | | - infobox = document.getElementById(info_id); |
160 | | - infobox.innerHTML = "$bad_url_error_str"; |
161 | | - return false; |
162 | | - } |
163 | | - } else if (type == 'email') { |
164 | | - // code borrowed from http://javascript.internet.com/forms/email-validation---basic.html |
165 | | - var email_regexp = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,6})+$/; |
166 | | - if (email_regexp.test(field.value)) { |
167 | | - return true; |
168 | | - } else { |
169 | | - infobox = document.getElementById(info_id); |
170 | | - infobox.innerHTML = "$bad_email_error_str"; |
171 | | - return false; |
172 | | - } |
173 | | - } else if (type == 'number') { |
174 | | - if (field.value.match(/^\-?[\d\.,]+$/)) { |
175 | | - return true; |
176 | | - } else { |
177 | | - infobox = document.getElementById(info_id); |
178 | | - infobox.innerHTML = "$bad_number_error_str"; |
179 | | - return false; |
180 | | - } |
181 | | - } else if (type == 'date') { |
182 | | - // validate only if day and year fields are both filled in |
183 | | - day_field = document.getElementById(field_id + "_day"); |
184 | | - year_field = document.getElementById(field_id + "_year"); |
185 | | - if (day_field.value == '' || year_field.value == '') { |
186 | | - return true; |
187 | | - } else if (day_field.value.match(/^\d+$/) && |
188 | | - day_field.value <= 31) { |
189 | | - // no year validation, since it can also include |
190 | | - // 'BC' and possibly other non-number strings |
191 | | - return true; |
192 | | - } else { |
193 | | - infobox = document.getElementById(info_id); |
194 | | - infobox.innerHTML = "$bad_date_error_str"; |
195 | | - return false; |
196 | | - } |
197 | | - } else { |
198 | | - return true; |
199 | | - } |
200 | | - } |
201 | | -} |
202 | | - |
203 | | -// same as validate_multiple_mandatory_fields(), but for type validation |
204 | | -function validate_type_of_multiple_fields(field_num, type) { |
205 | | - var num_errors = 0; |
206 | | - elems = document.getElementsByTagName("*"); |
207 | | - var field_pattern = new RegExp('input_(.*)_' + field_num); |
208 | | - for (var i = 0; i < elems.length; i++) { |
209 | | - id = elems[i].id; |
210 | | - if (matches = field_pattern.exec(id)) { |
211 | | - instance_num = matches[1]; |
212 | | - var input_name = "input_" + instance_num + "_" + field_num; |
213 | | - var info_name = "info_" + instance_num + "_" + field_num; |
214 | | - if (! validate_field_type(input_name, type, info_name)) { |
215 | | - num_errors += 1; |
216 | | - } |
217 | | - } |
218 | | - } |
219 | | - return (num_errors == 0); |
220 | | -} |
221 | | - |
222 | | - |
223 | | -function validate_all() { |
224 | | - var num_errors = 0; |
225 | | - |
226 | | -END; |
227 | | - foreach ( $sfgJSValidationCalls as $function_call ) { |
228 | | - $javascript_text .= " if (! $function_call) num_errors += 1;\n"; |
229 | | - } |
230 | | - $javascript_text .= <<<END |
231 | | - if (num_errors > 0) { |
232 | | - // add error header, if it's not there already |
233 | | - if (! document.getElementById("form_error_header")) { |
234 | | - var errorMsg = document.createElement('div'); |
235 | | - errorMsg.innerHTML = "<div id=\"form_error_header\" class=\"warningMessage\" style=\"font-size: medium\">$form_errors_header</div>"; |
236 | | - document.getElementById("contentSub").appendChild(errorMsg); |
237 | | - } |
238 | | - scroll(0, 0); |
239 | | - } |
240 | | - return (num_errors == 0); |
241 | | -} |
242 | | - |
243 | | -END; |
244 | | - return $javascript_text; |
245 | | - } |
246 | | - |
247 | | - static function instancesJavascript( $using_choosers ) { |
248 | | - $remove_text = wfMsg( 'sf_formedit_remove' ); |
249 | | - $javascript_text = <<<END |
250 | | - |
251 | | -var num_elements = 0; |
252 | | - |
253 | | -function addInstance(starter_div_id, main_div_id, tab_index) |
254 | | -{ |
255 | | - var starter_div = document.getElementById(starter_div_id); |
256 | | - var main_div = document.getElementById(main_div_id); |
257 | | - num_elements++; |
258 | | - |
259 | | - //Create the new instance |
260 | | - var new_div = starter_div.cloneNode(true); |
261 | | - var div_id = 'div_gen_' + num_elements; |
262 | | - new_div.className = 'multipleTemplate'; |
263 | | - new_div.id = div_id; |
264 | | - new_div.style.display = 'block'; |
265 | | - |
266 | | - // make internal ID unique for the relevant divs and spans, and replace |
267 | | - // the [num] index in the element names with an actual unique index |
268 | | - var children = new_div.getElementsByTagName('*'); |
269 | | - // this array is needed to counteract an IE bug |
270 | | - var orig_children = starter_div.getElementsByTagName('*'); |
271 | | - var x; |
272 | | - for (x = 0; x < children.length; x++) { |
273 | | - if (children[x].name) |
274 | | - children[x].name = children[x].name.replace(/\[num\]/g, '[' + num_elements + ']'); |
275 | | - if (children[x].id) |
276 | | - children[x].id = children[x].id |
277 | | - .replace(/input_/g, 'input_' + num_elements + '_') |
278 | | - .replace(/info_/g, 'info_' + num_elements + '_') |
279 | | - .replace(/div_/g, 'div_' + num_elements + '_'); |
280 | | - if (children[x].href) |
281 | | - children[x].href = children[x].href |
282 | | - .replace(/input_/g, 'input_' + num_elements + '_'); |
283 | | - // for dropdowns, copy over selectedIndex from original div, |
284 | | - // to get around a bug in IE |
285 | | - if (children[x].type == 'select-one') { |
286 | | - children[x].selectedIndex = orig_children[x].selectedIndex; |
287 | | - } |
288 | | - } |
289 | | - if (children[x]) { |
290 | | - //We clone the last object |
291 | | - if (children[x].href) { |
292 | | - children[x].href = children[x].href |
293 | | - .replace(/input_/g, 'input_' + num_elements + '_') |
294 | | - .replace(/info_/g, 'info_' + num_elements + '_') |
295 | | - .replace(/div_/g, 'div_' + num_elements + '_'); |
296 | | - } |
297 | | - } |
298 | | - // Since we clone the first object and we have uploadable field |
299 | | - // we must replace the input_ in order to let the printer return |
300 | | - // the value into the right field |
301 | | - //Create remove button |
302 | | - var remove_button = document.createElement('input'); |
303 | | - remove_button.type = 'button'; |
304 | | - remove_button.value = "$remove_text"; |
305 | | - remove_button.tabIndex = tab_index; |
306 | | - remove_button.onclick = removeInstanceEventHandler(div_id); |
307 | | - new_div.appendChild(remove_button); |
308 | | - |
309 | | - //Add the new instance |
310 | | - main_div.appendChild(new_div); |
311 | | - attachAutocompleteToAllFields(new_div); |
312 | | - |
313 | | - //In order to add the new instances in multiple floatBox (multiple templates) |
314 | | - fb.tagAnchors(self.document); |
315 | | - if ($using_choosers) { |
316 | | - hideOrShowFieldset(new_div); |
317 | | - } |
318 | | -} |
319 | | - |
320 | | -function removeInstanceEventHandler(this_div_id) |
321 | | -{ |
322 | | - return function() { |
323 | | - removeInstance(this_div_id); |
324 | | - }; |
325 | | -} |
326 | | - |
327 | | -function removeInstance(div_id) { |
328 | | - var olddiv = document.getElementById(div_id); |
329 | | - var parent = olddiv.parentNode; |
330 | | - parent.removeChild(olddiv); |
331 | | - if ($using_choosers) |
332 | | - hideOrShowFieldset(parent); |
333 | | -} |
334 | | - |
335 | | -END; |
336 | | - return $javascript_text; |
337 | | - } |
338 | | - |
339 | | - static function autocompletionJavascript() { |
340 | | - global $wgScriptPath; |
341 | | - |
342 | | - $javascript_text = <<<END |
343 | | -var autocompletemappings = new Array(); |
344 | | -var autocompletestrings = new Array(); |
345 | | -var autocompletedatatypes = new Array(); |
346 | | - |
347 | | -//Activate autocomplete functionality for every field on the document |
348 | | -function attachAutocompleteToAllDocumentFields() |
349 | | -{ |
350 | | - var forms = document.getElementsByTagName("form"); |
351 | | - var x; |
352 | | - for (x = 0; x < forms.length; x++) { |
353 | | - if (forms[x].name == "createbox") { |
354 | | - attachAutocompleteToAllFields(forms[x]); |
355 | | - } |
356 | | - } |
357 | | -} |
358 | | - |
359 | | -//Activate autocomplete functionality for every field under the specified element |
360 | | -function attachAutocompleteToAllFields(base) |
361 | | -{ |
362 | | - var inputs = base.getElementsByTagName("input"); |
363 | | - var y; |
364 | | - for (y = 0; y < inputs.length; y++) { |
365 | | - attachAutocompleteToField(inputs[y].id); |
366 | | - } |
367 | | - // don't forget the textareas |
368 | | - inputs = base.getElementsByTagName("textarea"); |
369 | | - for (y = 0; y < inputs.length; y++) { |
370 | | - attachAutocompleteToField(inputs[y].id); |
371 | | - } |
372 | | -} |
373 | | - |
374 | | -//Activate autocomplete functionality for the specified field |
375 | | -function attachAutocompleteToField(input_id) |
376 | | -{ |
377 | | - //Check input id for the proper format, to ensure this is for SF |
378 | | - if (input_id.substr(0,6) == 'input_') |
379 | | - { |
380 | | - //Extract the field ID number from the input field |
381 | | - var field_num = parseInt(input_id.substring(input_id.lastIndexOf('_') + 1, input_id.length),10); |
382 | | - //Add the autocomplete string, if a mapping exists. |
383 | | - var field_string = autocompletemappings[field_num]; |
384 | | - if (field_string) { |
385 | | - var div_id = input_id.replace(/input_/g, 'div_'); |
386 | | - var field_values = new Array(); |
387 | | - field_values = field_string.split(','); |
388 | | - var delimiter = null; |
389 | | - var data_source = field_values[0]; |
390 | | - if (field_values[1] == 'list') { |
391 | | - delimiter = ","; |
392 | | - if (field_values[2] != null) { |
393 | | - delimiter = field_values[2]; |
394 | | - } |
395 | | - } |
396 | | - if (autocompletestrings[field_string] != null) { |
397 | | - sf_autocomplete(input_id, div_id, autocompletestrings[field_string], null, null, delimiter, data_source); |
398 | | - } else { |
399 | | - sf_autocomplete(input_id, div_id, null, "{$wgScriptPath}/api.php", autocompletedatatypes[field_string], delimiter, data_source); |
400 | | - } |
401 | | - } |
402 | | - } |
403 | | -} |
404 | | - |
405 | | -YAHOO.util.Event.addListener(window, 'load', attachAutocompleteToAllDocumentFields); |
406 | | - |
407 | | -END; |
408 | | - return $javascript_text; |
409 | | - } |
410 | | - |
411 | | - static function hiddenFieldHTML( $input_name, $cur_value ) { |
412 | | - $input = self::buttonHTML( array( |
413 | | - 'type' => 'hidden', |
414 | | - 'name' => $input_name, |
415 | | - 'value' => $cur_value, |
416 | | - ) ); |
417 | | - return <<<END |
418 | | - $input |
419 | | - |
420 | | -END; |
421 | | - } |
422 | | - |
423 | | - /** |
424 | | - * Add a hidden input for each field in the template call that's |
425 | | - * not handled by the form itself |
426 | | - */ |
427 | | - static function unhandledFieldsHTML( $template_contents ) { |
428 | | - $text = ""; |
429 | | - foreach ( $template_contents as $key => $value ) { |
430 | | - if ( $key != '' && !is_numeric( $key ) ) |
431 | | - $text .= self::hiddenFieldHTML( "_unhandled_$key", $value ); |
432 | | - } |
433 | | - return $text; |
434 | | - } |
435 | | - |
436 | | - /** |
437 | | - * Add unhandled fields back into the template call that the form |
438 | | - * generates, so that editing with a form will have no effect on them |
439 | | - */ |
440 | | - static function addUnhandledFields() { |
441 | | - global $wgRequest; |
442 | | - $additional_template_text = ""; |
443 | | - foreach ( $wgRequest->getValues() as $key => $value ) { |
444 | | - if ( substr( $key, 0, 11 ) == '_unhandled_' ) { |
445 | | - $field_name = substr( $key, 11 ); |
446 | | - $additional_template_text .= "|$field_name=$value\n"; |
447 | | - } |
448 | | - } |
449 | | - return $additional_template_text; |
450 | | - } |
451 | | - |
452 | | - /** |
453 | | - * Helper function, for versions of MediaWiki that don't have |
454 | | - * Xml::expandAttributes (i.e., before 1.13) |
455 | | - */ |
456 | | - static function expandAttributes( $attribs ) { |
457 | | - if ( method_exists( 'Xml', 'expandAttributes' ) ) { |
458 | | - return Xml::expandAttributes( $attribs ); |
459 | | - } else { |
460 | | - $out = ''; |
461 | | - foreach ( $attribs as $name => $val ) |
462 | | - $out .= " {$name}=\"" . Sanitizer::encodeAttribute( $val ) . '"'; |
463 | | - return $out; |
464 | | - } |
465 | | - } |
466 | | - |
467 | | - static function summaryInputHTML( $is_disabled, $label = null, $attr = array() ) { |
468 | | - global $sfgTabIndex; |
469 | | - |
470 | | - $sfgTabIndex++; |
471 | | - if ( $label == null ) |
472 | | - $label = wfMsg( 'summary' ); |
473 | | - $disabled_text = ( $is_disabled ) ? " disabled" : ""; |
474 | | - $attr = self::expandAttributes( $attr ); |
475 | | - $text = <<<END |
476 | | - <span id='wpSummaryLabel'><label for='wpSummary'>$label</label></span> |
477 | | - <input tabindex="$sfgTabIndex" type='text' value="" name='wpSummary' id='wpSummary' maxlength='200' size='60'$disabled_text$attr/> |
478 | | - |
479 | | -END; |
480 | | - return $text; |
481 | | - } |
482 | | - |
483 | | - static function minorEditInputHTML( $is_disabled, $label = null, $attr = array() ) { |
484 | | - global $sfgTabIndex; |
485 | | - |
486 | | - $sfgTabIndex++; |
487 | | - $disabled_text = ( $is_disabled ) ? " disabled" : ""; |
488 | | - if ( $label == null ) |
489 | | - $label = wfMsgExt( 'minoredit', array( 'parseinline' ) ); |
490 | | - $accesskey = wfMsg( 'accesskey-minoredit' ); |
491 | | - $tooltip = wfMsg( 'tooltip-minoredit' ); |
492 | | - $attr = self::expandAttributes( $attr ); |
493 | | - $text = <<<END |
494 | | - <input tabindex="$sfgTabIndex" type="checkbox" value="1" name="wpMinoredit" accesskey="$accesskey" id="wpMinoredit"$disabled_text$attr/> |
495 | | - <label for="wpMinoredit" title="$tooltip">$label</label> |
496 | | - |
497 | | -END; |
498 | | - return $text; |
499 | | - } |
500 | | - |
501 | | - static function watchInputHTML( $is_disabled, $label = null, $attr = array() ) { |
502 | | - global $sfgTabIndex, $wgUser, $wgTitle; |
503 | | - |
504 | | - $sfgTabIndex++; |
505 | | - $checked_text = ""; |
506 | | - $disabled_text = ( $is_disabled ) ? " disabled" : ""; |
507 | | - // figure out if the checkbox should be checked - |
508 | | - // this code borrowed from /includes/EditPage.php |
509 | | - if ( $wgUser->getOption( 'watchdefault' ) ) { |
510 | | - # Watch all edits |
511 | | - $checked_text = " checked"; |
512 | | - } elseif ( $wgUser->getOption( 'watchcreations' ) && !$wgTitle->exists() ) { |
513 | | - # Watch creations |
514 | | - $checked_text = " checked"; |
515 | | - } elseif ( $wgTitle->userIsWatching() ) { |
516 | | - # Already watched |
517 | | - $checked_text = " checked"; |
518 | | - } |
519 | | - if ( $label == null ) |
520 | | - $label = wfMsgExt( 'watchthis', array( 'parseinline' ) ); |
521 | | - $accesskey = htmlspecialchars( wfMsg( 'accesskey-watch' ) ); |
522 | | - $tooltip = htmlspecialchars( wfMsg( 'tooltip-watch' ) ); |
523 | | - $attr = self::expandAttributes( $attr ); |
524 | | - $text = <<<END |
525 | | - <input tabindex="$sfgTabIndex" type="checkbox" name="wpWatchthis" accesskey="$accesskey" id='wpWatchthis'$checked_text$disabled_text$attr/> |
526 | | - <label for="wpWatchthis" title="$tooltip">$label</label> |
527 | | - |
528 | | -END; |
529 | | - return $text; |
530 | | - } |
531 | | - |
532 | | - /** |
533 | | - * Helper function to display a simple button |
534 | | - */ |
535 | | - static function buttonHTML( $values ) { |
536 | | - $button_html = Xml::element( 'input', $values, '' ); |
537 | | - return " $button_html\n"; |
538 | | - } |
539 | | - |
540 | | - static function saveButtonHTML( $is_disabled, $label = null, $attr = array() ) { |
541 | | - global $sfgTabIndex; |
542 | | - |
543 | | - $sfgTabIndex++; |
544 | | - if ( $label == null ) |
545 | | - $label = wfMsg( 'savearticle' ); |
546 | | - $temp = $attr + array( |
547 | | - 'id' => 'wpSave', |
548 | | - 'name' => 'wpSave', |
549 | | - 'type' => 'submit', |
550 | | - 'tabindex' => $sfgTabIndex, |
551 | | - 'value' => $label, |
552 | | - 'accesskey' => wfMsg( 'accesskey-save' ), |
553 | | - 'title' => wfMsg( 'tooltip-save' ), |
554 | | - ); |
555 | | - if ( $is_disabled ) { |
556 | | - $temp['disabled'] = ''; |
557 | | - } |
558 | | - return self::buttonHTML( $temp ); |
559 | | - } |
560 | | - |
561 | | - static function showPreviewButtonHTML( $is_disabled, $label = null, $attr = array() ) { |
562 | | - global $sfgTabIndex; |
563 | | - |
564 | | - $sfgTabIndex++; |
565 | | - if ( $label == null ) |
566 | | - $label = wfMsg( 'showpreview' ); |
567 | | - $temp = $attr + array( |
568 | | - 'id' => 'wpPreview', |
569 | | - 'name' => 'wpPreview', |
570 | | - 'type' => 'submit', |
571 | | - 'tabindex' => $sfgTabIndex, |
572 | | - 'value' => $label, |
573 | | - 'accesskey' => wfMsg( 'accesskey-preview' ), |
574 | | - 'title' => wfMsg( 'tooltip-preview' ), |
575 | | - ); |
576 | | - if ( $is_disabled ) { |
577 | | - $temp['disabled'] = ''; |
578 | | - } |
579 | | - return self::buttonHTML( $temp ); |
580 | | - } |
581 | | - |
582 | | - static function showChangesButtonHTML( $is_disabled, $label = null, $attr = array() ) { |
583 | | - global $sfgTabIndex; |
584 | | - |
585 | | - $sfgTabIndex++; |
586 | | - if ( $label == null ) |
587 | | - $label = wfMsg( 'showdiff' ); |
588 | | - $temp = $attr + array( |
589 | | - 'id' => 'wpDiff', |
590 | | - 'name' => 'wpDiff', |
591 | | - 'type' => 'submit', |
592 | | - 'tabindex' => $sfgTabIndex, |
593 | | - 'value' => $label, |
594 | | - 'accesskey' => wfMsg( 'accesskey-diff' ), |
595 | | - 'title' => wfMsg( 'tooltip-diff' ), |
596 | | - ); |
597 | | - if ( $is_disabled ) { |
598 | | - $temp['disabled'] = ''; |
599 | | - } |
600 | | - return self::buttonHTML( $temp ); |
601 | | - } |
602 | | - |
603 | | - static function cancelLinkHTML( $is_disabled, $label = null, $attr = array() ) { |
604 | | - global $wgUser, $wgTitle; |
605 | | - |
606 | | - $sk = $wgUser->getSkin(); |
607 | | - if ( $label == null ) |
608 | | - $label = wfMsgExt( 'cancel', array( 'parseinline' ) ); |
609 | | - if ( $wgTitle == null ) |
610 | | - $cancel = ''; |
611 | | - // if we're on the special 'FormEdit' page, just send the user |
612 | | - // back to the previous page they were on |
613 | | - elseif ( $wgTitle->getText() == 'FormEdit' |
614 | | - && $wgTitle->getNamespace() == NS_SPECIAL ) { |
615 | | - $cancel = '<a href="javascript:history.go(-1);">' . $label . '</a>'; |
616 | | - } else |
617 | | - $cancel = $sk->makeKnownLink( $wgTitle->getPrefixedText(), $label ); |
618 | | - $text = " <span class='editHelp'>$cancel</span>\n"; |
619 | | - return $text; |
620 | | - } |
621 | | - |
622 | | - static function runQueryButtonHTML( $is_disabled = false, $label = null, $attr = array() ) { |
623 | | - // is_disabled is currently ignored |
624 | | - global $sfgTabIndex; |
625 | | - |
626 | | - $sfgTabIndex++; |
627 | | - if ( $label == null ) |
628 | | - $label = wfMsg( 'runquery' ); |
629 | | - return self::buttonHTML( $attr + array( |
630 | | - 'id' => 'wpRunQuery', |
631 | | - 'name' => 'wpRunQuery', |
632 | | - 'type' => 'submit', |
633 | | - 'tabindex' => $sfgTabIndex, |
634 | | - 'value' => $label, |
635 | | - 'title' => $label, |
636 | | - ) ); |
637 | | - } |
638 | | - |
639 | | - // Much of this function is based on MediaWiki's EditPage::showEditForm() |
640 | | - static function formBottom( $is_disabled ) { |
641 | | - global $wgUser; |
642 | | - |
643 | | - $summary_text = SFFormUtils::summaryInputHTML( $is_disabled ); |
644 | | - $text = <<<END |
645 | | - <br /><br /> |
646 | | - <div class='editOptions'> |
647 | | -$summary_text <br /> |
648 | | - |
649 | | -END; |
650 | | - if ( $wgUser->isAllowed( 'minoredit' ) ) { |
651 | | - $text .= SFFormUtils::minorEditInputHTML( $is_disabled ); |
652 | | - } |
653 | | - |
654 | | - if ( $wgUser->isLoggedIn() ) { |
655 | | - $text .= SFFormUtils::watchInputHTML( $is_disabled ); |
656 | | - } |
657 | | - |
658 | | - $text .= <<<END |
659 | | - <br /> |
660 | | - <div class='editButtons'> |
661 | | - |
662 | | -END; |
663 | | - $text .= SFFormUtils::saveButtonHTML( $is_disabled ); |
664 | | - $text .= SFFormUtils::showPreviewButtonHTML( $is_disabled ); |
665 | | - $text .= SFFormUtils::showChangesButtonHTML( $is_disabled ); |
666 | | - $text .= SFFormUtils::cancelLinkHTML( $is_disabled ); |
667 | | - $text .= <<<END |
668 | | - </div><!-- editButtons --> |
669 | | - </div><!-- editOptions --> |
670 | | - |
671 | | -END; |
672 | | - return $text; |
673 | | - } |
674 | | - |
675 | | - // based on MediaWiki's EditPage::getPreloadedText() |
676 | | - static function getPreloadedText( $preload ) { |
677 | | - if ( $preload === '' ) { |
678 | | - return ''; |
679 | | - } else { |
680 | | - $preloadTitle = Title::newFromText( $preload ); |
681 | | - if ( isset( $preloadTitle ) && $preloadTitle->userCanRead() ) { |
682 | | - $rev = Revision::newFromTitle( $preloadTitle ); |
683 | | - if ( is_object( $rev ) ) { |
684 | | - $text = $rev->getText(); |
685 | | - // Remove <noinclude> sections and <includeonly> tags from text |
686 | | - $text = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $text ); |
687 | | - $text = strtr( $text, array( '<includeonly>' => '', '</includeonly>' => '' ) ); |
688 | | - return $text; |
689 | | - } |
690 | | - } |
691 | | - return ''; |
692 | | - } |
693 | | - } |
694 | | - |
695 | | - /** |
696 | | - * Used by 'RunQuery' page |
697 | | - */ |
698 | | - static function queryFormBottom() { |
699 | | - return self::runQueryButtonHTML( false ); |
700 | | - } |
701 | | - |
702 | | - static function getMonthNames() { |
703 | | - return array( |
704 | | - wfMsgForContent( 'january' ), |
705 | | - wfMsgForContent( 'february' ), |
706 | | - wfMsgForContent( 'march' ), |
707 | | - wfMsgForContent( 'april' ), |
708 | | - wfMsgForContent( 'may' ), |
709 | | - wfMsgForContent( 'june' ), |
710 | | - wfMsgForContent( 'july' ), |
711 | | - wfMsgForContent( 'august' ), |
712 | | - wfMsgForContent( 'september' ), |
713 | | - wfMsgForContent( 'october' ), |
714 | | - wfMsgForContent( 'november' ), |
715 | | - wfMsgForContent( 'december' ) |
716 | | - ); |
717 | | - } |
718 | | - |
719 | | - static function getShowFCKEditor() { |
720 | | - global $wgUser, $wgDefaultUserOptions; |
721 | | - |
722 | | - $showFCKEditor = 0; |
723 | | - if ( !$wgUser->getOption( 'riched_start_disabled', $wgDefaultUserOptions['riched_start_disabled'] ) ) { |
724 | | - $showFCKEditor += RTE_VISIBLE; |
725 | | - } |
726 | | - if ( $wgUser->getOption( 'riched_use_popup', $wgDefaultUserOptions['riched_use_popup'] ) ) { |
727 | | - $showFCKEditor += RTE_POPUP; |
728 | | - } |
729 | | - if ( $wgUser->getOption( 'riched_use_toggle', $wgDefaultUserOptions['riched_use_toggle'] ) ) { |
730 | | - $showFCKEditor += RTE_TOGGLE_LINK; |
731 | | - } |
732 | | - |
733 | | - if ( ( !empty( $_SESSION['showMyFCKeditor'] ) ) && ( $wgUser->getOption( 'riched_toggle_remember_state' ) ) ) |
734 | | - { |
735 | | - // clear RTE_VISIBLE flag |
736 | | - $showFCKEditor &= ~RTE_VISIBLE ; |
737 | | - // get flag from session |
738 | | - $showFCKEditor |= $_SESSION['showMyFCKeditor'] ; |
739 | | - } |
740 | | - return $showFCKEditor; |
741 | | - } |
742 | | - |
743 | | - static function prepareTextForFCK( $text ) { |
744 | | - global $wgTitle; |
745 | | - |
746 | | - $options = new FCKeditorParserOptions(); |
747 | | - $options->setTidy( true ); |
748 | | - $parser = new FCKeditorParser(); |
749 | | - $parser->setOutputType( OT_HTML ); |
750 | | - $text = $parser->parse( $text, $wgTitle, $options )->getText(); |
751 | | - return $text; |
752 | | - } |
753 | | - |
754 | | - static function mainFCKJavascript( $showFCKEditor ) { |
755 | | - global $wgUser, $wgScriptPath, $wgFCKEditorExtDir, $wgFCKEditorDir, $wgFCKEditorToolbarSet, $wgFCKEditorHeight; |
756 | | - |
757 | | - $newWinMsg = wfMsg( 'rich_editor_new_window' ); |
758 | | - $javascript_text = ' |
759 | | -var showFCKEditor = ' . $showFCKEditor . '; |
760 | | -var popup = false; //pointer to popup document |
761 | | -var firstLoad = true; |
762 | | -var editorMsgOn = "' . wfMsg( 'textrichditor' ) . '"; |
763 | | -var editorMsgOff = "' . wfMsg( 'tog-riched_disable' ) . '"; |
764 | | -var editorLink = "' . ( ( $showFCKEditor & RTE_VISIBLE ) ? wfMsg( 'tog-riched_disable' ): wfMsg( 'textrichditor' ) ) . '"; |
765 | | -var saveSetting = ' . ( $wgUser->getOption( 'riched_toggle_remember_state' ) ? 1 : 0 ) . '; |
766 | | -var RTE_VISIBLE = ' . RTE_VISIBLE . '; |
767 | | -var RTE_TOGGLE_LINK = ' . RTE_TOGGLE_LINK . '; |
768 | | -var RTE_POPUP = ' . RTE_POPUP . '; |
769 | | -'; |
770 | | - |
771 | | - $javascript_text .= <<<END |
772 | | -var oFCKeditor = new FCKeditor( "free_text" ); |
773 | | - |
774 | | -//Set config |
775 | | -oFCKeditor.BasePath = '$wgScriptPath/$wgFCKEditorDir/'; |
776 | | -oFCKeditor.Config["CustomConfigurationsPath"] = "$wgScriptPath/$wgFCKEditorExtDir/fckeditor_config.js" ; |
777 | | -oFCKeditor.Config["EditorAreaCSS"] = "$wgScriptPath/$wgFCKEditorExtDir/css/fckeditor.css" ; |
778 | | -oFCKeditor.ToolbarSet = "$wgFCKEditorToolbarSet" ; |
779 | | -oFCKeditor.ready = true; |
780 | | - |
781 | | -//IE hack to call func from popup |
782 | | -function FCK_sajax(func_name, args, target) { |
783 | | - sajax_request_type = 'POST' ; |
784 | | - sajax_do_call(func_name, args, function (x) { |
785 | | - // I know this is function, not object |
786 | | - target(x); |
787 | | - } |
788 | | - ); |
789 | | -} |
790 | | - |
791 | | -function onLoadFCKeditor() |
792 | | -{ |
793 | | - if (!(showFCKEditor & RTE_VISIBLE)) |
794 | | - showFCKEditor += RTE_VISIBLE; |
795 | | - firstLoad = false; |
796 | | - realTextarea = document.getElementById('free_text'); |
797 | | - if ( realTextarea ) |
798 | | - { |
799 | | - // Create the editor instance and replace the textarea. |
800 | | - oFCKeditor.Height = 300; |
801 | | - oFCKeditor.ReplaceTextarea() ; |
802 | | - |
803 | | - FCKeditorInsertTags = function (tagOpen, tagClose, sampleText, oDoc) |
804 | | - { |
805 | | - var txtarea; |
806 | | - |
807 | | - if ( !(typeof(oDoc.FCK) == "undefined") && !(typeof(oDoc.FCK.EditingArea) == "undefined") ) |
808 | | - { |
809 | | - txtarea = oDoc.FCK.EditingArea.Textarea ; |
810 | | - } |
811 | | - else if (oDoc.editform) |
812 | | - { |
813 | | - // if we have FCK enabled, behave differently... |
814 | | - if ( showFCKEditor & RTE_VISIBLE ) |
815 | | - { |
816 | | - SRCiframe = oDoc.getElementById ('free_text___Frame') ; |
817 | | - if ( SRCiframe ) |
818 | | - { |
819 | | - if (window.frames[SRCiframe]) |
820 | | - SRCdoc = window.frames[SRCiframe].oDoc ; |
821 | | - else |
822 | | - SRCdoc = SRCiframe.contentDocument ; |
823 | | - |
824 | | - var SRCarea = SRCdoc.getElementById ('xEditingArea').firstChild ; |
825 | | - |
826 | | - if (SRCarea) |
827 | | - txtarea = SRCarea ; |
828 | | - else |
829 | | - return false ; |
830 | | - |
831 | | - } |
832 | | - else |
833 | | - { |
834 | | - return false ; |
835 | | - } |
836 | | - } |
837 | | - else |
838 | | - { |
839 | | - txtarea = oDoc.editform.free_text ; |
840 | | - } |
841 | | - } |
842 | | - else |
843 | | - { |
844 | | - // some alternate form? take the first one we can find |
845 | | - var areas = oDoc.getElementsByTagName( 'textarea' ) ; |
846 | | - txtarea = areas[0] ; |
847 | | - } |
848 | | - |
849 | | - var selText, isSample = false ; |
850 | | - |
851 | | - if ( oDoc.selection && oDoc.selection.createRange ) |
852 | | - { // IE/Opera |
853 | | - |
854 | | - //save window scroll position |
855 | | - if ( oDoc.documentElement && oDoc.documentElement.scrollTop ) |
856 | | - var winScroll = oDoc.documentElement.scrollTop ; |
857 | | - else if ( oDoc.body ) |
858 | | - var winScroll = oDoc.body.scrollTop ; |
859 | | - |
860 | | - //get current selection |
861 | | - txtarea.focus() ; |
862 | | - var range = oDoc.selection.createRange() ; |
863 | | - selText = range.text ; |
864 | | - //insert tags |
865 | | - checkSelected(); |
866 | | - range.text = tagOpen + selText + tagClose ; |
867 | | - //mark sample text as selected |
868 | | - if ( isSample && range.moveStart ) |
869 | | - { |
870 | | - if (window.opera) |
871 | | - tagClose = tagClose.replace(/\\n/g,'') ; //check it out one more time |
872 | | - range.moveStart('character', - tagClose.length - selText.length) ; |
873 | | - range.moveEnd('character', - tagClose.length) ; |
874 | | - } |
875 | | - range.select(); |
876 | | - //restore window scroll position |
877 | | - if ( oDoc.documentElement && oDoc.documentElement.scrollTop ) |
878 | | - oDoc.documentElement.scrollTop = winScroll ; |
879 | | - else if ( oDoc.body ) |
880 | | - oDoc.body.scrollTop = winScroll ; |
881 | | - |
882 | | - } |
883 | | - else if ( txtarea.selectionStart || txtarea.selectionStart == '0' ) |
884 | | - { // Mozilla |
885 | | - |
886 | | - //save textarea scroll position |
887 | | - var textScroll = txtarea.scrollTop ; |
888 | | - //get current selection |
889 | | - txtarea.focus() ; |
890 | | - var startPos = txtarea.selectionStart ; |
891 | | - var endPos = txtarea.selectionEnd ; |
892 | | - selText = txtarea.value.substring( startPos, endPos ) ; |
893 | | - |
894 | | - //insert tags |
895 | | - if (!selText) |
896 | | - { |
897 | | - selText = sampleText ; |
898 | | - isSample = true ; |
899 | | - } |
900 | | - else if (selText.charAt(selText.length - 1) == ' ') |
901 | | - { //exclude ending space char |
902 | | - selText = selText.substring(0, selText.length - 1) ; |
903 | | - tagClose += ' ' ; |
904 | | - } |
905 | | - txtarea.value = txtarea.value.substring(0, startPos) + tagOpen + selText + tagClose + |
906 | | - txtarea.value.substring(endPos, txtarea.value.length) ; |
907 | | - //set new selection |
908 | | - if (isSample) |
909 | | - { |
910 | | - txtarea.selectionStart = startPos + tagOpen.length ; |
911 | | - txtarea.selectionEnd = startPos + tagOpen.length + selText.length ; |
912 | | - } |
913 | | - else |
914 | | - { |
915 | | - txtarea.selectionStart = startPos + tagOpen.length + selText.length + tagClose.length ; |
916 | | - txtarea.selectionEnd = txtarea.selectionStart; |
917 | | - } |
918 | | - //restore textarea scroll position |
919 | | - txtarea.scrollTop = textScroll; |
920 | | - } |
921 | | - } |
922 | | - } |
923 | | -} |
924 | | -function checkSelected() |
925 | | -{ |
926 | | - if (!selText) { |
927 | | - selText = sampleText; |
928 | | - isSample = true; |
929 | | - } else if (selText.charAt(selText.length - 1) == ' ') { //exclude ending space char |
930 | | - selText = selText.substring(0, selText.length - 1); |
931 | | - tagClose += ' ' |
932 | | - } |
933 | | -} |
934 | | -function initEditor() |
935 | | -{ |
936 | | - var toolbar = document.getElementById('free_text'); |
937 | | - //show popup or toogle link |
938 | | - if (showFCKEditor & (RTE_POPUP|RTE_TOGGLE_LINK)){ |
939 | | - var fckTools = document.createElement('div'); |
940 | | - fckTools.setAttribute('id', 'fckTools'); |
941 | | - |
942 | | - var SRCtextarea = document.getElementById( "free_text" ) ; |
943 | | - if (showFCKEditor & RTE_VISIBLE) SRCtextarea.style.display = "none"; |
944 | | - } |
945 | | - |
946 | | - if (showFCKEditor & RTE_TOGGLE_LINK) |
947 | | - { |
948 | | - fckTools.innerHTML='[<a class="fckToogle" id="toggle_free_text" href="javascript:void(0)" onclick="ToggleFCKEditor(\'toggle\',\'free_text\')">'+ editorLink +'</a>] '; |
949 | | - } |
950 | | - if (showFCKEditor & RTE_POPUP) |
951 | | - { |
952 | | - var style = (showFCKEditor & RTE_VISIBLE) ? 'style="display:none"' : ""; |
953 | | - fckTools.innerHTML+='<span ' + style + ' id="popup_free_text">[<a class="fckPopup" href="javascript:void(0)" onclick="ToggleFCKEditor(\'popup\',\'free_text\')">{$newWinMsg}</a>]</span>'; |
954 | | - } |
955 | | - |
956 | | - if (showFCKEditor & (RTE_POPUP|RTE_TOGGLE_LINK)){ |
957 | | - //add new toolbar before wiki toolbar |
958 | | - toolbar.parentNode.insertBefore( fckTools, toolbar ); |
959 | | - } |
960 | | - |
961 | | - if (showFCKEditor & RTE_VISIBLE) |
962 | | - { |
963 | | - if ( toolbar ) //insert wiki buttons |
964 | | - { |
965 | | - mwSetupToolbar = function() { return false ; } ; |
966 | | - |
967 | | - for (var i = 0; i < mwEditButtons.length; i++) { |
968 | | - mwInsertEditButton(toolbar, mwEditButtons[i]); |
969 | | - } |
970 | | - for (var i = 0; i < mwCustomEditButtons.length; i++) { |
971 | | - mwInsertEditButton(toolbar, mwCustomEditButtons[i]); |
972 | | - } |
973 | | - } |
974 | | - onLoadFCKeditor(); |
975 | | - } |
976 | | - return true; |
977 | | -} |
978 | | -addOnloadHook( initEditor ); |
979 | | - |
980 | | -END; |
981 | | - return $javascript_text; |
982 | | - } |
983 | | - |
984 | | - static function FCKToggleJavascript() { |
985 | | - // add toggle link and handler |
986 | | - $javascript_text = <<<END |
987 | | - |
988 | | -function ToggleFCKEditor(mode, objId) |
989 | | -{ |
990 | | - var SRCtextarea = document.getElementById( objId ) ; |
991 | | - if(mode == 'popup'){ |
992 | | - if (( showFCKEditor & RTE_VISIBLE) && ( FCKeditorAPI )) //if FCKeditor is up-to-date |
993 | | - { |
994 | | - var oEditorIns = FCKeditorAPI.GetInstance( objId ); |
995 | | - var text = oEditorIns.GetData( oEditorIns.Config.FormatSource ); |
996 | | - SRCtextarea.value = text; //copy text to textarea |
997 | | - } |
998 | | - FCKeditor_OpenPopup('oFCKeditor',objId); |
999 | | - return true; |
1000 | | - } |
1001 | | - |
1002 | | - var oToggleLink = document.getElementById('toggle_'+ objId ); |
1003 | | - var oPopupLink = document.getElementById('popup_'+ objId ); |
1004 | | - |
1005 | | - if ( firstLoad ) |
1006 | | - { |
1007 | | - // firstLoad = true => FCKeditor start invisible |
1008 | | - // "innerHTML" fails for IE - use "innerText" instead |
1009 | | - if (oToggleLink) { |
1010 | | - if (oToggleLink.innerText) |
1011 | | - oToggleLink.innerText = "Loading..."; |
1012 | | - else |
1013 | | - oToggleLink.innerHTML = "Loading..."; |
1014 | | - } |
1015 | | - sajax_request_type = 'POST' ; |
1016 | | - oFCKeditor.ready = false; |
1017 | | - sajax_do_call('wfSajaxWikiToHTML', [SRCtextarea.value], function ( result ){ |
1018 | | - if ( firstLoad ) //still |
1019 | | - { |
1020 | | - SRCtextarea.value = result.responseText; //insert parsed text |
1021 | | - onLoadFCKeditor(); |
1022 | | - // "innerHTML" fails for IE - use "innerText" instead |
1023 | | - if (oToggleLink) { |
1024 | | - if (oToggleLink.innerText) |
1025 | | - oToggleLink.innerText = editorMsgOff; |
1026 | | - else |
1027 | | - oToggleLink.innerHTML = editorMsgOff; |
1028 | | - } |
1029 | | - oFCKeditor.ready = true; |
1030 | | - } |
1031 | | - }); |
1032 | | - return true; |
1033 | | - } |
1034 | | - |
1035 | | - if (!oFCKeditor.ready) return false; //sajax_do_call in action |
1036 | | - if (!FCKeditorAPI) return false; //not loaded yet |
1037 | | - var oEditorIns = FCKeditorAPI.GetInstance( objId ); |
1038 | | - var oEditorIframe = document.getElementById( objId+'___Frame' ); |
1039 | | - var FCKtoolbar = document.getElementById('toolbar'); |
1040 | | - var bIsWysiwyg = ( oEditorIns.EditMode == FCK_EDITMODE_WYSIWYG ); |
1041 | | - |
1042 | | - //FCKeditor visible -> hidden |
1043 | | - if ( showFCKEditor & RTE_VISIBLE) |
1044 | | - { |
1045 | | - var text = oEditorIns.GetData( oEditorIns.Config.FormatSource ); |
1046 | | - SRCtextarea.value = text; |
1047 | | - if ( bIsWysiwyg ) oEditorIns.SwitchEditMode(); //switch to plain |
1048 | | - var text = oEditorIns.GetData( oEditorIns.Config.FormatSource ); |
1049 | | - //copy from FCKeditor to textarea |
1050 | | - SRCtextarea.value = text; |
1051 | | - if (saveSetting) |
1052 | | - { |
1053 | | - sajax_request_type = 'GET' ; |
1054 | | - sajax_do_call( 'wfSajaxToggleFCKeditor', ['hide'], function(){} ) ; //remember closing in session |
1055 | | - } |
1056 | | - if (oToggleLink) { |
1057 | | - if (oToggleLink.innerText) |
1058 | | - oToggleLink.innerText = editorMsgOn; |
1059 | | - else |
1060 | | - oToggleLink.innerHTML = editorMsgOn; |
1061 | | - } |
1062 | | - if (oPopupLink) oPopupLink.style.display = ''; |
1063 | | - showFCKEditor -= RTE_VISIBLE; |
1064 | | - oEditorIframe.style.display = 'none'; |
1065 | | - //FCKtoolbar.style.display = ''; |
1066 | | - SRCtextarea.style.display = ''; |
1067 | | - } |
1068 | | - //FCKeditor hidden -> visible |
1069 | | - else |
1070 | | - { |
1071 | | - if ( bIsWysiwyg ) oEditorIns.SwitchEditMode(); //switch to plain |
1072 | | - SRCtextarea.style.display = 'none'; |
1073 | | - //copy from textarea to FCKeditor |
1074 | | - oEditorIns.EditingArea.Textarea.value = SRCtextarea.value |
1075 | | - //FCKtoolbar.style.display = 'none'; |
1076 | | - oEditorIframe.style.display = ''; |
1077 | | - if ( !bIsWysiwyg ) oEditorIns.SwitchEditMode(); //switch to WYSIWYG |
1078 | | - showFCKEditor += RTE_VISIBLE; |
1079 | | - if (oToggleLink) { |
1080 | | - if (oToggleLink.innerText) |
1081 | | - oToggleLink.innerText = editorMsgOff; |
1082 | | - else |
1083 | | - oToggleLink.innerHTML = editorMsgOff; |
1084 | | - } |
1085 | | - if (oPopupLink) oPopupLink.style.display = 'none'; |
1086 | | - } |
1087 | | - return true; |
1088 | | -} |
1089 | | - |
1090 | | -END; |
1091 | | - return $javascript_text; |
1092 | | - } |
1093 | | - |
1094 | | - static function FCKPopupJavascript() { |
1095 | | - global $wgFCKEditorExtDir; |
1096 | | - $javascript_text = <<<END |
1097 | | - |
1098 | | -function FCKeditor_OpenPopup(jsID, textareaID) |
1099 | | -{ |
1100 | | - popupUrl = '${wgFCKEditorExtDir}/FCKeditor.popup.html'; |
1101 | | - popupUrl = popupUrl + '?var='+ jsID + '&el=' + textareaID; |
1102 | | - window.open(popupUrl, null, 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=1,dependent=yes'); |
1103 | | - return 0; |
1104 | | -} |
1105 | | - |
1106 | | -END; |
1107 | | - return $javascript_text; |
1108 | | - } |
1109 | | -} |
Index: trunk/extensions/SemanticForms/includes/SF_FormInputs.inc |
— | — | @@ -1,895 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Helper functions to display the various inputs of a user-generated form |
5 | | - * |
6 | | - * @author Yaron Koren |
7 | | - * @author Jeffrey Stuckman |
8 | | - * @author Matt Williamson |
9 | | - * @author Patrick Nagel |
10 | | - */ |
11 | | - |
12 | | -class SFFormInputs { |
13 | | - |
14 | | - /** |
15 | | - * Create a comma-delimited string of values that match the specified |
16 | | - * source name and type, for use by Javascript autocompletion. |
17 | | - */ |
18 | | - static function createAutocompleteValuesString( $source_name, $source_type ) { |
19 | | - $names_array = array(); |
20 | | - // the query depends on whether this is a property, category, concept |
21 | | - // or namespace |
22 | | - if ( $source_type == 'property' || $source_type == 'attribute' || $source_type == 'relation' ) { |
23 | | - $names_array = SFUtils::getAllValuesForProperty( $source_name ); |
24 | | - } elseif ( $source_type == 'category' ) { |
25 | | - $names_array = SFUtils::getAllPagesForCategory( $source_name, 10 ); |
26 | | - } elseif ( $source_type == 'concept' ) { |
27 | | - $names_array = SFUtils::getAllPagesForConcept( $source_name ); |
28 | | - } else { // i.e., $source_type == 'namespace' |
29 | | - // switch back to blank for main namespace |
30 | | - if ( $source_name == "Main" ) |
31 | | - $source_name = ""; |
32 | | - $names_array = SFUtils::getAllPagesForNamespace( $source_name ); |
33 | | - } |
34 | | - // escape quotes, to avoid Javascript errors |
35 | | - $names_array = array_map( 'addslashes', $names_array ); |
36 | | - $autocomplete_string = "[['" . implode( "'], ['", $names_array ) . "']]"; |
37 | | - // replace any newlines in the string, just to avoid breaking the Javascript |
38 | | - $autocomplete_string = str_replace( "\n", ' ', $autocomplete_string ); |
39 | | - $autocomplete_string = str_replace( "\r", ' ', $autocomplete_string ); |
40 | | - return $autocomplete_string; |
41 | | - } |
42 | | - |
43 | | - static function uploadLinkHTML( $input_id, $delimiter = null, $default_filename = null ) { |
44 | | - $upload_window_page = SpecialPage::getPage( 'UploadWindow' ); |
45 | | - $query_string = "sfInputID=$input_id"; |
46 | | - if ( $delimiter != null ) |
47 | | - $query_string .= "&sfDelimiter=$delimiter"; |
48 | | - if ( $default_filename != null ) |
49 | | - $query_string .= "&wpDestFile=$default_filename"; |
50 | | - $upload_window_url = $upload_window_page->getTitle()->getFullURL( $query_string ); |
51 | | - $upload_label = wfMsg( 'upload' ); |
52 | | - // window needs to be bigger for MediaWiki version 1.16+ |
53 | | - if ( class_exists( 'HTMLForm' ) ) |
54 | | - $style = "width:650 height:500"; |
55 | | - else |
56 | | - $style = ''; |
57 | | - $text = " <a href=\"$upload_window_url\" title=\"$upload_label\" rel=\"iframe\" rev=\"$style\">$upload_label</a>"; |
58 | | - return $text; |
59 | | - } |
60 | | - |
61 | | - static function textEntryHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
62 | | - // if it's an autocomplete, call the with-autocomplete function instead |
63 | | - if ( array_key_exists( 'autocompletion source', $other_args ) ) { |
64 | | - return self::textInputWithAutocompleteHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
65 | | - } |
66 | | - |
67 | | - // if there are possible values specified, call the dropdown function |
68 | | - if ( array_key_exists( 'possible_values', $other_args ) && $other_args['possible_values'] != null ) |
69 | | - return SFFormInputs::dropdownHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
70 | | - |
71 | | - global $sfgTabIndex, $sfgFieldNum, $sfgJSValidationCalls; |
72 | | - |
73 | | - $className = ( $is_mandatory ) ? "createboxInput mandatoryField" : "createboxInput"; |
74 | | - if ( array_key_exists( 'class', $other_args ) ) |
75 | | - $className .= " " . $other_args['class']; |
76 | | - $input_id = "input_$sfgFieldNum"; |
77 | | - $info_id = "info_$sfgFieldNum"; |
78 | | - // set size based on pre-set size, or field type - if field type is set, |
79 | | - // possibly add validation too |
80 | | - if ( array_key_exists( 'size', $other_args ) ) { |
81 | | - $size = $other_args['size']; |
82 | | - } elseif ( array_key_exists( 'field_type', $other_args ) ) { |
83 | | - $validation_type_str = ""; |
84 | | - if ( $other_args['field_type'] == 'integer' ) { |
85 | | - $size = 10; |
86 | | - $validation_type_str = 'integer'; |
87 | | - } elseif ( $other_args['field_type'] == 'number' ) { |
88 | | - $size = 10; |
89 | | - $validation_type_str = 'number'; |
90 | | - } elseif ( $other_args['field_type'] == 'URL' ) { |
91 | | - $size = 100; |
92 | | - $validation_type_str = 'URL'; |
93 | | - } elseif ( $other_args['field_type'] == 'email' ) { |
94 | | - $size = 45; |
95 | | - $validation_type_str = 'email'; |
96 | | - } else { |
97 | | - $size = 35; |
98 | | - } |
99 | | - if ( $validation_type_str != '' ) { |
100 | | - if ( array_key_exists( 'part_of_multiple', $other_args ) ) { |
101 | | - $sfgJSValidationCalls[] = "validate_type_of_multiple_fields($sfgFieldNum, '$validation_type_str')"; |
102 | | - } else { |
103 | | - $sfgJSValidationCalls[] = "validate_field_type('$input_id', '$validation_type_str', '$info_id')"; |
104 | | - } |
105 | | - } |
106 | | - } else { |
107 | | - $size = 35; |
108 | | - } |
109 | | - if ( ! is_null( $cur_value ) && ! is_array( $cur_value ) ) |
110 | | - $cur_value = htmlspecialchars( $cur_value ); |
111 | | - |
112 | | - $text = <<<END |
113 | | - <input id="$input_id" tabindex="$sfgTabIndex" class="$className" name="$input_name" type="text" value="$cur_value" size="$size" |
114 | | -END; |
115 | | - if ( $is_disabled ) |
116 | | - $text .= " disabled"; |
117 | | - if ( array_key_exists( 'maxlength', $other_args ) ) |
118 | | - $text .= ' maxlength="' . $other_args['maxlength'] . '"'; |
119 | | - $text .= <<<END |
120 | | -/> |
121 | | - <span id="$info_id" class="errorMessage"></span> |
122 | | - |
123 | | -END; |
124 | | - if ( array_key_exists( 'is_uploadable', $other_args ) && $other_args['is_uploadable'] == true ) { |
125 | | - if ( array_key_exists( 'is_list', $other_args ) && $other_args['is_list'] == true ) { |
126 | | - if ( array_key_exists( 'delimiter', $other_args ) ) { |
127 | | - $delimiter = $other_args['delimiter']; |
128 | | - } else { |
129 | | - $delimiter = ","; |
130 | | - } |
131 | | - } else { |
132 | | - $delimiter = null; |
133 | | - } |
134 | | - if ( array_key_exists( 'default filename', $other_args ) ) { |
135 | | - $default_filename = $other_args['default filename']; |
136 | | - } else { |
137 | | - $default_filename = ""; |
138 | | - } |
139 | | - $text .= SFFormInputs::uploadLinkHTML( $input_id, $delimiter, $default_filename ); |
140 | | - } |
141 | | - return array( $text, null ); |
142 | | - } |
143 | | - |
144 | | - static function dropdownHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
145 | | - global $sfgTabIndex, $sfgFieldNum; |
146 | | - |
147 | | - $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
148 | | - if ( array_key_exists( 'class', $other_args ) ) |
149 | | - $className .= " " . $other_args['class']; |
150 | | - $input_id = "input_$sfgFieldNum"; |
151 | | - $info_id = "info_$sfgFieldNum"; |
152 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
153 | | - $javascript_text = ''; |
154 | | - $return_js_text = ''; |
155 | | - if ( array_key_exists( 'show on select', $other_args ) ) { |
156 | | - $javascript_text = 'onChange="'; |
157 | | - foreach ( $other_args['show on select'] as $div_id => $options ) { |
158 | | - $options_str = implode( "', '", $options ); |
159 | | - $this_js_text = "showIfSelected('$input_id', ['$options_str'], '$div_id'); "; |
160 | | - $javascript_text .= $this_js_text; |
161 | | - $return_js_text .= $this_js_text . "\n"; |
162 | | - } |
163 | | - $javascript_text .= '"'; |
164 | | - } |
165 | | - $text = <<<END |
166 | | - <select id="$input_id" tabindex="$sfgTabIndex" name="$input_name" class="$className" $disabled_text $javascript_text> |
167 | | - |
168 | | -END; |
169 | | - // add a blank value at the beginning, unless this is a mandatory field |
170 | | - // and there's a current value in place (either through a default value |
171 | | - // or because we're editing an existing page) |
172 | | - if ( ! $is_mandatory || $cur_value == '' ) { |
173 | | - $text .= " <option value=\"\"></option>\n"; |
174 | | - } |
175 | | - if ( ( $possible_values = $other_args['possible_values'] ) == null ) |
176 | | - $possible_values = array(); |
177 | | - foreach ( $possible_values as $possible_value ) { |
178 | | - $text .= " <option value=\"$possible_value\""; |
179 | | - if ( $possible_value == $cur_value ) { $text .= " selected=\"selected\""; } |
180 | | - $text .= ">"; |
181 | | - if ( array_key_exists( 'value_labels', $other_args ) && is_array( $other_args['value_labels'] ) && array_key_exists( $possible_value, $other_args['value_labels'] ) ) |
182 | | - $text .= htmlspecialchars( $other_args['value_labels'][$possible_value] ); |
183 | | - else |
184 | | - $text .= $possible_value; |
185 | | - $text .= "</option>\n"; |
186 | | - } |
187 | | - $text .= <<<END |
188 | | - </select> |
189 | | - <span id="$info_id" class="errorMessage"></span> |
190 | | - |
191 | | -END; |
192 | | - return array( $text, $return_js_text ); |
193 | | - } |
194 | | - |
195 | | - /** |
196 | | - * Helper function to get an array of values out of what may be either |
197 | | - * an array or a delimited string |
198 | | - */ |
199 | | - static function getValuesArray( $value, $delimiter ) { |
200 | | - if ( is_array( $value ) ) { |
201 | | - return $value; |
202 | | - } else { |
203 | | - // remove extra spaces |
204 | | - return array_map( 'trim', explode( $delimiter, $value ) ); |
205 | | - } |
206 | | - } |
207 | | - |
208 | | - static function listboxHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
209 | | - global $sfgTabIndex, $sfgFieldNum; |
210 | | - |
211 | | - $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
212 | | - if ( array_key_exists( 'class', $other_args ) ) |
213 | | - $className .= " " . $other_args['class']; |
214 | | - $input_id = "input_$sfgFieldNum"; |
215 | | - $info_id = "info_$sfgFieldNum"; |
216 | | - $hidden_input_name = $input_name . "[is_list]"; |
217 | | - $input_name .= "[]"; // needed so that this input will send an array |
218 | | - if ( array_key_exists( 'size', $other_args ) ) |
219 | | - $size_text = "size=" . $other_args['size']; |
220 | | - else |
221 | | - $size_text = ""; |
222 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
223 | | - // get list delimiter - default is comma |
224 | | - if ( array_key_exists( 'delimiter', $other_args ) ) { |
225 | | - $delimiter = $other_args['delimiter']; |
226 | | - } else { |
227 | | - $delimiter = ","; |
228 | | - } |
229 | | - $cur_values = self::getValuesArray( $cur_value, $delimiter ); |
230 | | - |
231 | | - $javascript_text = ''; |
232 | | - $return_js_text = ''; |
233 | | - if ( array_key_exists( 'show on select', $other_args ) ) { |
234 | | - $javascript_text = 'onChange="'; |
235 | | - foreach ( $other_args['show on select'] as $div_id => $options ) { |
236 | | - $options_str = implode( "', '", $options ); |
237 | | - $this_js_text = "showIfSelected('$input_id', ['$options_str'], '$div_id'); "; |
238 | | - $javascript_text .= $this_js_text; |
239 | | - $return_js_text .= $this_js_text . "\n"; |
240 | | - } |
241 | | - $javascript_text .= '"'; |
242 | | - } |
243 | | - |
244 | | - $text = <<<END |
245 | | - <select id="$input_id" tabindex="$sfgTabIndex" name="$input_name" class="$className" multiple $size_text $disabled_text $javascript_text> |
246 | | - |
247 | | -END; |
248 | | - if ( ( $possible_values = $other_args['possible_values'] ) == null ) |
249 | | - $possible_values = array(); |
250 | | - foreach ( $possible_values as $possible_value ) { |
251 | | - $text .= " <option value=\"$possible_value\""; |
252 | | - if ( in_array( $possible_value, $cur_values ) ) { $text .= " selected"; } |
253 | | - $text .= ">"; |
254 | | - if ( array_key_exists( 'value_labels', $other_args ) && is_array( $other_args['value_labels'] ) && array_key_exists( $possible_value, $other_args['value_labels'] ) ) |
255 | | - $text .= htmlspecialchars( $other_args['value_labels'][$possible_value] ); |
256 | | - else |
257 | | - $text .= $possible_value; |
258 | | - $text .= "</option>\n"; |
259 | | - } |
260 | | - $text .= <<<END |
261 | | - </select> |
262 | | - <span id="$info_id" class="errorMessage"></span> |
263 | | - <input type="hidden" name="$hidden_input_name" value="1" /> |
264 | | - |
265 | | -END; |
266 | | - return array( $text, $return_js_text ); |
267 | | - } |
268 | | - |
269 | | - static function checkboxesHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
270 | | - global $sfgTabIndex, $sfgFieldNum; |
271 | | - |
272 | | - $checkbox_class = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
273 | | - $span_class = "checkboxSpan"; |
274 | | - if ( array_key_exists( 'class', $other_args ) ) |
275 | | - $span_class .= " " . $other_args['class']; |
276 | | - $input_id = "input_$sfgFieldNum"; |
277 | | - $info_id = "info_$sfgFieldNum"; |
278 | | - $hidden_input_name = $input_name . "[is_list]"; |
279 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
280 | | - // get list delimiter - default is comma |
281 | | - if ( array_key_exists( 'delimiter', $other_args ) ) { |
282 | | - $delimiter = $other_args['delimiter']; |
283 | | - } else { |
284 | | - $delimiter = ","; |
285 | | - } |
286 | | - $cur_values = self::getValuesArray( $cur_value, $delimiter ); |
287 | | - |
288 | | - if ( ( $possible_values = $other_args['possible_values'] ) == null ) |
289 | | - $possible_values = array(); |
290 | | - $text = ""; |
291 | | - $return_js_text = ""; |
292 | | - $enum_input_ids = array(); |
293 | | - // if it's mandatory, add a span around all the checkboxes, since |
294 | | - // some browsers don't support formatting of checkboxes |
295 | | - if ( $is_mandatory ) |
296 | | - $text .= ' <span class="mandatoryFieldsSpan">' . "\n"; |
297 | | - foreach ( $possible_values as $key => $possible_value ) { |
298 | | - // create array $enum_input_ids to associate values with their input IDs, |
299 | | - // for use in creating the 'show on select' Javascript later |
300 | | - $enum_input_ids[$possible_value] = $input_id; |
301 | | - $cur_input_name = $input_name . "[" . $key . "]"; |
302 | | - $checked_text = ( in_array( $possible_value, $cur_values ) ) ? 'checked="checked"' : ""; |
303 | | - |
304 | | - if ( array_key_exists( 'value_labels', $other_args ) && is_array( $other_args['value_labels'] ) && array_key_exists( $possible_value, $other_args['value_labels'] ) ) |
305 | | - $label = htmlspecialchars( $other_args['value_labels'][$possible_value] ); |
306 | | - else |
307 | | - $label = $possible_value; |
308 | | - $text .= <<<END |
309 | | - <span class="$span_class"><input type="checkbox" id="$input_id" tabindex="$sfgTabIndex" name="$cur_input_name" value="$possible_value" class="$checkbox_class" $checked_text $disabled_text/> $label</span> |
310 | | - |
311 | | -END; |
312 | | - $sfgTabIndex++; |
313 | | - $sfgFieldNum++; |
314 | | - $input_id = "input_$sfgFieldNum"; |
315 | | - } |
316 | | - // close span |
317 | | - if ( $is_mandatory ) |
318 | | - $text .= " </span>"; |
319 | | - $text .= <<<END |
320 | | - <span id="$info_id" class="errorMessage"></span> |
321 | | - <input type="hidden" name="$hidden_input_name" value="1" /> |
322 | | - |
323 | | -END; |
324 | | - |
325 | | - $return_js_text = ''; |
326 | | - if ( array_key_exists( 'show on select', $other_args ) ) { |
327 | | - foreach ( $other_args['show on select'] as $div_id => $options ) { |
328 | | - $cur_input_ids = array(); |
329 | | - foreach ( $options as $option ) { |
330 | | - if ( array_key_exists( $option, $enum_input_ids ) ) { |
331 | | - $cur_input_ids[] = $enum_input_ids[$option]; |
332 | | - } |
333 | | - } |
334 | | - $options_str = "['" . implode( "', '", $cur_input_ids ) . "']"; |
335 | | - $cur_js_text = "showIfChecked($options_str, '$div_id'); "; |
336 | | - $return_js_text .= $cur_js_text . "\n"; |
337 | | - foreach ( $possible_values as $key => $possible_value ) { |
338 | | - $cur_input_id = $enum_input_ids[$possible_value]; |
339 | | - // we use addClickHandler(), instead of adding the Javascript via |
340 | | - // onClick="", because MediaWiki's wikibits.js does its own handling |
341 | | - // of checkboxes, which impacts their behavior in IE |
342 | | - if ( in_array( $possible_value, $options ) ) { |
343 | | - $return_js_text .= <<<END |
344 | | -addClickHandler( |
345 | | - document.getElementById('$cur_input_id'), |
346 | | - function() { $cur_js_text } |
347 | | -); |
348 | | - |
349 | | -END; |
350 | | - } |
351 | | - } |
352 | | - } |
353 | | - } |
354 | | - |
355 | | - // do the replacements |
356 | | - foreach ( $enum_input_ids as $enum_val => $input_id ) { |
357 | | - $return_js_text = str_replace( "<<$enum_val>>", "'$input_id'", $return_js_text ); |
358 | | - } |
359 | | - return array( $text, $return_js_text ); |
360 | | - } |
361 | | - |
362 | | - static function textInputWithAutocompleteHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
363 | | - // if 'no autocomplete' was specified, print a regular text entry instead |
364 | | - if ( array_key_exists( 'no autocomplete', $other_args ) && |
365 | | - $other_args['no autocomplete'] == true ) { |
366 | | - unset( $other_args['autocompletion source'] ); |
367 | | - return SFFormInputs::textEntryHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
368 | | - } |
369 | | - // if a set of values was specified, print a dropdown instead |
370 | | - if ( array_key_exists( 'possible_values', $other_args ) && $other_args['possible_values'] != null ) |
371 | | - return SFFormInputs::dropdownHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
372 | | - |
373 | | - global $sfgTabIndex, $sfgFieldNum; |
374 | | - |
375 | | - $className = ( $is_mandatory ) ? "autocompleteInput mandatoryField" : "autocompleteInput createboxInput"; |
376 | | - if ( array_key_exists( 'class', $other_args ) ) |
377 | | - $className .= " " . $other_args['class']; |
378 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
379 | | - if ( array_key_exists( 'autocomplete field type', $other_args ) ) { |
380 | | - $autocomplete_field_type = $other_args['autocomplete field type']; |
381 | | - $autocompletion_source = $other_args['autocompletion source']; |
382 | | - if ( $autocomplete_field_type != 'external_url' ) { |
383 | | - global $wgContLang; |
384 | | - $autocompletion_source = $wgContLang->ucfirst( $autocompletion_source ); |
385 | | - } |
386 | | - } |
387 | | - $input_id = "input_" . $sfgFieldNum; |
388 | | - $info_id = "info_" . $sfgFieldNum; |
389 | | - $div_name = "div_" . $sfgFieldNum; |
390 | | - if ( array_key_exists( 'input_type', $other_args ) && $other_args['input_type'] == "textarea" ) { |
391 | | - $rows = $other_args['rows']; |
392 | | - $cols = $other_args['cols']; |
393 | | - if ( array_key_exists( 'maxlength', $other_args ) ) { |
394 | | - $maxlength = $other_args['maxlength']; |
395 | | - // is this an unnecessary performance load? Get the substring of the |
396 | | - // text on every key press or release, regardless of the current length |
397 | | - // of the text |
398 | | - $js_call = " onKeyDown=\"this.value = this.value.substring(0, $maxlength);\" onKeyUp=\"this.value = this.value.substring(0, $maxlength);\""; |
399 | | - } else { |
400 | | - $js_call = ""; |
401 | | - } |
402 | | - $text = <<<END |
403 | | - <textarea tabindex="$sfgTabIndex" id="$input_id" name="$input_name" rows="$rows" cols="$cols" class="$className" $disabled_text $js_call></textarea> |
404 | | - |
405 | | -END; |
406 | | - } else { |
407 | | - if ( array_key_exists( 'size', $other_args ) ) |
408 | | - $size = $other_args['size']; |
409 | | - else |
410 | | - $size = "35"; |
411 | | - |
412 | | - $text = <<<END |
413 | | - <input tabindex="$sfgTabIndex" id="$input_id" name="$input_name" type="text" value="" size="$size" class="$className" |
414 | | -END; |
415 | | - if ( $is_disabled ) |
416 | | - $text .= " disabled"; |
417 | | - if ( array_key_exists( 'maxlength', $other_args ) ) |
418 | | - $text .= ' maxlength="' . $other_args['maxlength'] . '"'; |
419 | | - $text .= "/>\n"; |
420 | | - } |
421 | | - // is_list and delimiter variables - needed later |
422 | | - $is_list = ( array_key_exists( 'is_list', $other_args ) && $other_args['is_list'] == true ); |
423 | | - if ( $is_list ) { |
424 | | - if ( array_key_exists( 'delimiter', $other_args ) ) { |
425 | | - $delimiter = $other_args['delimiter']; |
426 | | - } else { |
427 | | - $delimiter = ","; |
428 | | - } |
429 | | - } else { |
430 | | - $delimiter = null; |
431 | | - } |
432 | | - if ( array_key_exists( 'is_uploadable', $other_args ) && $other_args['is_uploadable'] == true ) { |
433 | | - if ( array_key_exists( 'default filename', $other_args ) ) { |
434 | | - $default_filename = $other_args['default filename']; |
435 | | - } else { |
436 | | - $default_filename = ""; |
437 | | - } |
438 | | - $text .= SFFormInputs::uploadLinkHTML( $input_id, $delimiter, $default_filename ); |
439 | | - } |
440 | | - $text .= <<<END |
441 | | - <span id="$info_id" class="errorMessage"></span> |
442 | | - <div class="page_name_auto_complete" id="$div_name"></div> |
443 | | -<script type="text/javascript">/* <![CDATA[ */ |
444 | | - |
445 | | -END; |
446 | | - $options_str_key = str_replace( "'", "\'", $autocompletion_source ); |
447 | | - if ( $is_list ) { |
448 | | - $options_str_key .= ",list"; |
449 | | - if ( $delimiter != "," ) { |
450 | | - $options_str_key .= "," . $delimiter; |
451 | | - } |
452 | | - } |
453 | | - $javascript_text = "autocompletemappings[$sfgFieldNum] = '$options_str_key';\n"; |
454 | | - if ( array_key_exists( 'remote autocompletion', $other_args ) && |
455 | | - $other_args['remote autocompletion'] == true ) { |
456 | | - $javascript_text .= "autocompletedatatypes['$options_str_key'] = '$autocomplete_field_type';\n"; |
457 | | - } elseif ( $autocompletion_source != '' ) { |
458 | | - $autocomplete_string = self::createAutocompleteValuesString( $autocompletion_source, $autocomplete_field_type ); |
459 | | - $javascript_text .= "autocompletestrings['$options_str_key'] = $autocomplete_string;\n"; |
460 | | - } |
461 | | - if ( $cur_value ) { |
462 | | - // replace various values to not break the Javascript |
463 | | - $cur_value = str_replace( '"', '\"', $cur_value ); |
464 | | - $cur_value = str_replace( "\n", '\n', $cur_value ); |
465 | | - $cur_value = str_replace( "\r", '\r', $cur_value ); |
466 | | - $text .= "document.getElementById('$input_id').value = \"$cur_value\"\n"; |
467 | | - } |
468 | | - $text .= "/* ]]> */</script>\n"; |
469 | | - return array( $text, $javascript_text ); |
470 | | - } |
471 | | - |
472 | | - static function textAreaHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
473 | | - // set size values |
474 | | - if ( ! array_key_exists( 'rows', $other_args ) ) |
475 | | - $other_args['rows'] = 5; |
476 | | - if ( ! array_key_exists( 'cols', $other_args ) ) |
477 | | - $other_args['cols'] = 80; |
478 | | - |
479 | | - // if it's an autocomplete, call the with-autocomplete function instead |
480 | | - if ( array_key_exists( 'autocompletion source', $other_args ) ) { |
481 | | - $other_args['input_type'] = "textarea"; |
482 | | - return SFFormInputs::textInputWithAutocompleteHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
483 | | - } |
484 | | - |
485 | | - global $sfgTabIndex, $sfgFieldNum; |
486 | | - |
487 | | - $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
488 | | - if ( array_key_exists( 'class', $other_args ) ) |
489 | | - $className .= " " . $other_args['class']; |
490 | | - $info_id = "info_$sfgFieldNum"; |
491 | | - // use a special ID for the free text field, for FCK's needs |
492 | | - $input_id = $input_name == "free_text" ? "free_text" : "input_$sfgFieldNum"; |
493 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
494 | | - |
495 | | - $rows = $other_args['rows']; |
496 | | - $cols = $other_args['cols']; |
497 | | - if ( array_key_exists( 'maxlength', $other_args ) ) { |
498 | | - $maxlength = $other_args['maxlength']; |
499 | | - // is this an unnecessary performance load? Get the substring of the |
500 | | - // text on every key press or release, regardless of the current length |
501 | | - // of the text |
502 | | - $js_call = " onKeyDown=\"this.value = this.value.substring(0, $maxlength);\" onKeyUp=\"this.value = this.value.substring(0, $maxlength);\""; |
503 | | - } else { |
504 | | - $js_call = ""; |
505 | | - } |
506 | | - |
507 | | - $cur_value = htmlspecialchars( $cur_value ); |
508 | | - $text = <<<END |
509 | | - <textarea tabindex="$sfgTabIndex" id="$input_id" name="$input_name" rows="$rows" cols="$cols" class="$className" $disabled_text $js_call>$cur_value</textarea> |
510 | | - <span id="$info_id" class="errorMessage"></span> |
511 | | - |
512 | | -END; |
513 | | - return array( $text, null ); |
514 | | - } |
515 | | - |
516 | | - static function monthDropdownHTML( $cur_month, $input_name, $is_disabled ) { |
517 | | - global $sfgTabIndex, $sfgFieldNum, $wgAmericanDates; |
518 | | - |
519 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
520 | | - $text = ' <select tabindex="' . $sfgTabIndex . '" id="input_' . $sfgFieldNum . '_month" name="' . $input_name . "[month]\" $disabled_text>\n"; |
521 | | - $month_names = SFFormUtils::getMonthNames(); |
522 | | - foreach ( $month_names as $i => $name ) { |
523 | | - // pad out month to always be two digits |
524 | | - $month_value = ( $wgAmericanDates == true ) ? $name : str_pad( $i + 1, 2, "0", STR_PAD_LEFT ); |
525 | | - $text .= " <option value=\"$month_value\""; |
526 | | - if ( $name == $cur_month || ( $i + 1 ) == $cur_month ) { $text .= " selected=\"selected\""; } |
527 | | - $text .= ">$name</option>\n"; |
528 | | - } |
529 | | - $text .= " </select>\n"; |
530 | | - return $text; |
531 | | - } |
532 | | - |
533 | | - static function dateEntryHTML( $date, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
534 | | - global $sfgTabIndex, $sfgFieldNum, $sfgJSValidationCalls, $wgAmericanDates; |
535 | | - |
536 | | - $input_id = "input_$sfgFieldNum"; |
537 | | - $info_id = "info_$sfgFieldNum"; |
538 | | - // add to validation calls |
539 | | - if ( array_key_exists( 'part_of_multiple', $other_args ) ) { |
540 | | - $sfgJSValidationCalls[] = "validate_type_of_multiple_fields($sfgFieldNum, 'date')"; |
541 | | - } else { |
542 | | - $sfgJSValidationCalls[] = "validate_field_type('$input_id', 'date', '$info_id')"; |
543 | | - } |
544 | | - |
545 | | - if ( $date ) { |
546 | | - // can show up here either as an array or a string, depending on |
547 | | - // whether it came from user input or a wiki page |
548 | | - if ( is_array( $date ) ) { |
549 | | - $year = $date['year']; |
550 | | - $month = $date['month']; |
551 | | - $day = $date['day']; |
552 | | - } else { |
553 | | - // handle 'default=now' |
554 | | - if ( $date == 'now' ) $date = date( 'Y/m/d' ); |
555 | | - $actual_date = new SMWTimeValue( '_dat' ); |
556 | | - $actual_date->setUserValue( $date ); |
557 | | - $year = $actual_date->getYear(); |
558 | | - // TODO - the code to convert from negative to BC notation should |
559 | | - // be in SMW itself |
560 | | - if ( $year < 0 ) { $year = ( $year * - 1 + 1 ) . " BC"; } |
561 | | - $month = $actual_date->getMonth(); |
562 | | - $day = $actual_date->getDay(); |
563 | | - } |
564 | | - } else { |
565 | | - $cur_date = getdate(); |
566 | | - $year = $cur_date['year']; |
567 | | - $month = $cur_date['month']; |
568 | | - $day = null; // no need for day |
569 | | - } |
570 | | - $text = ""; |
571 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
572 | | - if ( $wgAmericanDates ) { |
573 | | - $text .= SFFormInputs::monthDropdownHTML( $month, $input_name, $is_disabled ); |
574 | | - $text .= ' <input tabindex="' . $sfgTabIndex . '" id="' . $input_id . '_day" name="' . $input_name . '[day]" type="text" value="' . $day . '" size="2" ' . $disabled_text . '/>' . "\n"; |
575 | | - } else { |
576 | | - $text .= ' <input tabindex="' . $sfgTabIndex . '" id="' . $input_id . '_day" name="' . $input_name . '[day]" type="text" value="' . $day . '" size="2" ' . $disabled_text . '/>' . "\n"; |
577 | | - $text .= SFFormInputs::monthDropdownHTML( $month, $input_name, $is_disabled ); |
578 | | - } |
579 | | - $text .= ' <input tabindex="' . $sfgTabIndex . '" id="' . $input_id . '_year" name="' . $input_name . '[year]" type="text" value="' . $year . '" size="4" ' . $disabled_text . '/>' . "\n"; |
580 | | - $text .= " <span id=\"$info_id\" class=\"errorMessage\"></span>"; |
581 | | - return array( $text, null ); |
582 | | - } |
583 | | - |
584 | | - static function dateTimeEntryHTML( $datetime, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
585 | | - global $sfgTabIndex, $sfg24HourTime; |
586 | | - |
587 | | - $include_timezone = $other_args['include_timezone']; |
588 | | - |
589 | | - if ( $datetime ) { |
590 | | - // can show up here either as an array or a string, depending on |
591 | | - // whether it came from user input or a wiki page |
592 | | - if ( is_array( $datetime ) ) { |
593 | | - if ( isset( $datetime['hour'] ) ) $hour = $datetime['hour']; |
594 | | - if ( isset( $datetime['minute'] ) ) $minute = $datetime['minute']; |
595 | | - if ( isset( $datetime['second'] ) ) $second = $datetime['second']; |
596 | | - if ( ! $sfg24HourTime ) { |
597 | | - if ( isset( $datetime['ampm24h'] ) ) $ampm24h = $datetime['ampm24h']; |
598 | | - } |
599 | | - if ( isset( $datetime['timezone'] ) ) $timezone = $datetime['timezone']; |
600 | | - } else { |
601 | | - // TODO - this should change to use SMW's own date-handling class, |
602 | | - // just like dateEntryHTML() does |
603 | | - $actual_date = strtotime( $datetime ); |
604 | | - if ( $sfg24HourTime ) { |
605 | | - $hour = date( "G", $actual_date ); |
606 | | - } else { |
607 | | - $hour = date( "g", $actual_date ); |
608 | | - } |
609 | | - $minute = date( "i", $actual_date ); |
610 | | - $second = date( "s", $actual_date ); |
611 | | - if ( ! $sfg24HourTime ) { |
612 | | - $ampm24h = date( "A", $actual_date ); |
613 | | - } |
614 | | - $timezone = date( "T", $actual_date ); |
615 | | - } |
616 | | - } else { |
617 | | - $cur_date = getdate(); |
618 | | - $hour = null; |
619 | | - $minute = null; |
620 | | - $second = "00"; // default at least this value |
621 | | - $ampm24h = ""; |
622 | | - $timezone = ""; |
623 | | - } |
624 | | - |
625 | | - list( $text, $javascript_text ) = SFFormInputs::dateEntryHTML( $datetime, $input_name, $is_mandatory, $is_disabled, $other_args ); |
626 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
627 | | - $text .= ' <input tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[hour]" type="text" value="' . $hour . '" size="2"/ ' . $disabled_text . '>'; |
628 | | - $sfgTabIndex++; |
629 | | - $text .= ' :<input tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[minute]" type="text" value="' . $minute . '" size="2"/ ' . $disabled_text . '>'; |
630 | | - $sfgTabIndex++; |
631 | | - $text .= ':<input tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[second]" type="text" value="' . $second . '" size="2"/ ' . $disabled_text . '>' . "\n"; |
632 | | - |
633 | | - if ( ! $sfg24HourTime ) { |
634 | | - $sfgTabIndex++; |
635 | | - $text .= ' <select tabindex="' . $sfgTabIndex . '" name="' . $input_name . "[ampm24h]\" $disabled_text>\n"; |
636 | | - $ampm24h_options = array( '', 'AM', 'PM' ); |
637 | | - foreach ( $ampm24h_options as $value ) { |
638 | | - $text .= " <option value=\"$value\""; |
639 | | - if ( $value == $ampm24h ) { $text .= " selected=\"selected\""; } |
640 | | - $text .= ">$value</option>\n"; |
641 | | - } |
642 | | - $text .= " </select>\n"; |
643 | | - } |
644 | | - |
645 | | - if ( $include_timezone ) { |
646 | | - $sfgTabIndex++; |
647 | | - $text .= ' <input tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[timezone]" type="text" value="' . $timezone . '" size="2"/ ' . $disabled_text . '>' . "\n"; |
648 | | - } |
649 | | - |
650 | | - return array( $text, $javascript_text ); |
651 | | - } |
652 | | - |
653 | | - static function radioButtonHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
654 | | - global $sfgTabIndex, $sfgFieldNum; |
655 | | - |
656 | | - $input_id = "input_$sfgFieldNum"; |
657 | | - $info_id = "info_$sfgFieldNum"; |
658 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
659 | | - $check_set = false; |
660 | | - $javascript_text = ''; |
661 | | - $return_js_text = ''; |
662 | | - if ( array_key_exists( 'show on select', $other_args ) ) { |
663 | | - $javascript_text = 'onClick="'; |
664 | | - foreach ( $other_args['show on select'] as $div_id => $options ) { |
665 | | - $options_str = implode( "', '", $options ); |
666 | | - $this_js_text = "showIfSelected('$input_id', ['$options_str'], '$div_id'); "; |
667 | | - $javascript_text .= $this_js_text; |
668 | | - $return_js_text .= $this_js_text . "\n"; |
669 | | - } |
670 | | - $javascript_text .= '"'; |
671 | | - } |
672 | | - $text = ""; |
673 | | - // if it's mandatory, add a span around all the radiobuttons, since |
674 | | - // some browsers don't support formatting of radiobuttons |
675 | | - if ( $is_mandatory ) |
676 | | - $text .= ' <span class="mandatoryFieldsSpan">' . "\n"; |
677 | | - |
678 | | - // start with an initial "None" value, unless this is a mandatory field |
679 | | - // and there's a current value in place (either through a default value |
680 | | - // or because we're editing an existing page) |
681 | | - if ( ! $is_mandatory || $cur_value == '' ) { |
682 | | - $text .= ' <input type="radio" id="' . $input_id . '" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '" value=""'; |
683 | | - if ( ! $cur_value ) { |
684 | | - $text .= ' checked="checked"'; |
685 | | - $check_set = true; |
686 | | - } |
687 | | - $text .= " $disabled_text $javascript_text/> " . wfMsg( 'sf_formedit_none' ) . "\n"; |
688 | | - } |
689 | | - |
690 | | - if ( ( $possible_values = $other_args['possible_values'] ) == null ) |
691 | | - $possible_values = array(); |
692 | | - foreach ( $possible_values as $i => $possible_value ) { |
693 | | - $text .= ' <input type="radio" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '" value="' . $possible_value . '"'; |
694 | | - if ( $cur_value == $possible_value || ( ! $cur_value && ! $check_set ) ) { |
695 | | - $text .= ' checked="checked"'; |
696 | | - $check_set = true; |
697 | | - } |
698 | | - if ( array_key_exists( 'value_labels', $other_args ) && is_array( $other_args['value_labels'] ) && array_key_exists( $possible_value, $other_args['value_labels'] ) ) |
699 | | - $label = htmlspecialchars( $other_args['value_labels'][$possible_value] ); |
700 | | - else |
701 | | - $label = $possible_value; |
702 | | - $text .= " $disabled_text $javascript_text/> $label\n"; |
703 | | - } |
704 | | - // close span |
705 | | - if ( $is_mandatory ) |
706 | | - $text .= " </span>"; |
707 | | - $text .= <<<END |
708 | | - <span id="$info_id" class="errorMessage"></span> |
709 | | - |
710 | | -END; |
711 | | - return array( $text, $return_js_text ); |
712 | | - } |
713 | | - |
714 | | - static function checkboxHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
715 | | - global $sfgTabIndex, $sfgFieldNum; |
716 | | - |
717 | | - $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
718 | | - if ( array_key_exists( 'class', $other_args ) ) |
719 | | - $className .= " " . $other_args['class']; |
720 | | - $info_id = "info_$sfgFieldNum"; |
721 | | - $input_id = "input_$sfgFieldNum"; |
722 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
723 | | - $return_js_text = ''; |
724 | | - if ( array_key_exists( 'show on select', $other_args ) ) { |
725 | | - $div_id = key( $other_args['show on select'] ); |
726 | | - $this_js_text = "showIfChecked(['$input_id'], '$div_id');"; |
727 | | - // we use addClickHandler(), instead of adding the Javascript via |
728 | | - // onClick="", because MediaWiki's wikibits.js does its own handling |
729 | | - // of checkboxes, which impacts their behavior in IE |
730 | | - $return_js_text = <<<END |
731 | | -$this_js_text; |
732 | | -addClickHandler( |
733 | | - document.getElementById("$input_id"), |
734 | | - function() { $this_js_text } |
735 | | -); |
736 | | - |
737 | | -END; |
738 | | - } |
739 | | - |
740 | | - // can show up here either as an array or a string, depending on |
741 | | - // whether it came from user input or a wiki page |
742 | | - if ( is_array( $cur_value ) ) { |
743 | | - $checked_str = ( array_key_exists( 'value', $cur_value ) && $cur_value['value'] == 'on' ) ? ' checked="checked"' : ""; |
744 | | - } else { |
745 | | - // default to false - no need to check if it matches a 'false' word |
746 | | - $vlc = strtolower( trim( $cur_value ) ); |
747 | | - // manually load SMW's message values, if they weren't loaded before |
748 | | - wfLoadExtensionMessages( 'SemanticMediaWiki' ); |
749 | | - if ( in_array( $vlc, explode( ',', wfMsgForContent( 'smw_true_words' ) ), TRUE ) ) { |
750 | | - $checked_str = ' checked="checked"'; |
751 | | - } else { |
752 | | - $checked_str = ""; |
753 | | - } |
754 | | - } |
755 | | - $text = <<<END |
756 | | - <input name="{$input_name}[is_checkbox]" type="hidden" value="true" /> |
757 | | - <input id="$input_id" name="{$input_name}[value]" type="checkbox" class="$className" tabindex="$sfgTabIndex" $checked_str $disabled_text/> |
758 | | - <span id="$info_id" class="errorMessage"></span> |
759 | | - |
760 | | -END; |
761 | | - return array( $text, $return_js_text ); |
762 | | - } |
763 | | - |
764 | | - static function categoryHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
765 | | - // escape if CategoryTree extension isn't included |
766 | | - if ( ! function_exists( 'efCategoryTreeParserHook' ) ) |
767 | | - return array( null, null ); |
768 | | - |
769 | | - global $sfgTabIndex, $sfgFieldNum; |
770 | | - |
771 | | - $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
772 | | - if ( array_key_exists( 'class', $other_args ) ) |
773 | | - $className .= " " . $other_args['class']; |
774 | | - if ( array_key_exists( 'top category', $other_args ) ) { |
775 | | - $top_category = $other_args['top category']; |
776 | | - } else { |
777 | | - // escape - we can't do anything |
778 | | - return array( null, null ); |
779 | | - } |
780 | | - if ( array_key_exists( 'height', $other_args ) ) { |
781 | | - $height = $other_args['height']; |
782 | | - } else { |
783 | | - $height = "100"; |
784 | | - } |
785 | | - if ( array_key_exists( 'width', $other_args ) ) { |
786 | | - $width = $other_args['width']; |
787 | | - } else { |
788 | | - $width = "500"; |
789 | | - } |
790 | | - $input_id = "input_$sfgFieldNum"; |
791 | | - $info_id = "info_$sfgFieldNum"; |
792 | | - |
793 | | - $text = '<div style="overflow: auto; padding: 5px; border: 1px #aaaaaa solid; max-height: ' . $height . 'px; width: ' . $width . 'px;">'; |
794 | | - |
795 | | - // start with an initial "None" value, unless this is a mandatory field |
796 | | - // and there's a current value in place (either through a default value |
797 | | - // or because we're editing an existing page) |
798 | | - if ( ! $is_mandatory || $cur_value == '' ) { |
799 | | - $input_id = "input_$sfgFieldNum"; |
800 | | - $info_id = "info_$sfgFieldNum"; |
801 | | - $text .= ' <input type="radio" id="' . $input_id . '" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '" value=""'; |
802 | | - if ( ! $cur_value ) { |
803 | | - $text .= ' checked="checked"'; |
804 | | - $check_set = true; |
805 | | - } |
806 | | - $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
807 | | - $text .= " $disabled_text/> <em>" . wfMsg( 'sf_formedit_none' ) . "</em>\n"; |
808 | | - } |
809 | | - |
810 | | - global $wgCategoryTreeMaxDepth; |
811 | | - $wgCategoryTreeMaxDepth = 10; |
812 | | - $tree = efCategoryTreeParserHook( $top_category, array( 'mode' => 'categories', 'depth' => 10 ) ); |
813 | | - $tree = preg_replace( '/(<a class="CategoryTreeLabel.*>)(.*)(<\/a>)/', '<input id="' . $input_id . '" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '" value="$2" type="radio"> $1$2$3', $tree ); |
814 | | - $tree = str_replace( "value=\"$cur_value\"", "value=\"$cur_value\" checked=\"checked\"", $tree ); |
815 | | - // if it's disabled, set all to disabled |
816 | | - if ( $is_disabled ) { |
817 | | - $tree = str_replace( 'type="radio"', 'type="radio" disabled', $tree ); |
818 | | - } |
819 | | - $text .= $tree . '</div>'; |
820 | | - |
821 | | - $text .= <<<END |
822 | | - <span id="$info_id" class="errorMessage"></span> |
823 | | - |
824 | | -END; |
825 | | - |
826 | | - return array( $text, null ); |
827 | | - } |
828 | | - |
829 | | - static function categoriesHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
830 | | - // escape if CategoryTree extension isn't included |
831 | | - if ( ! function_exists( 'efCategoryTreeParserHook' ) ) |
832 | | - return array( null, null ); |
833 | | - |
834 | | - global $sfgTabIndex, $sfgFieldNum; |
835 | | - |
836 | | - $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
837 | | - if ( array_key_exists( 'class', $other_args ) ) |
838 | | - $className .= " " . $other_args['class']; |
839 | | - $input_id = "input_$sfgFieldNum"; |
840 | | - $info_id = "info_$sfgFieldNum"; |
841 | | - $hidden_input_name = $input_name . "[is_list]"; |
842 | | - // get list delimiter - default is comma |
843 | | - if ( array_key_exists( 'delimiter', $other_args ) ) { |
844 | | - $delimiter = $other_args['delimiter']; |
845 | | - } else { |
846 | | - $delimiter = ","; |
847 | | - } |
848 | | - $cur_values = self::getValuesArray( $cur_value, $delimiter ); |
849 | | - if ( array_key_exists( 'top category', $other_args ) ) { |
850 | | - $top_category = $other_args['top category']; |
851 | | - } else { |
852 | | - // escape - we can't do anything |
853 | | - return array( null, null ); |
854 | | - } |
855 | | - if ( array_key_exists( 'height', $other_args ) ) { |
856 | | - $height = $other_args['height']; |
857 | | - } else { |
858 | | - $height = "100"; |
859 | | - } |
860 | | - if ( array_key_exists( 'width', $other_args ) ) { |
861 | | - $width = $other_args['width']; |
862 | | - } else { |
863 | | - $width = "500"; |
864 | | - } |
865 | | - |
866 | | - global $wgCategoryTreeMaxDepth; |
867 | | - $wgCategoryTreeMaxDepth = 10; |
868 | | - $tree = efCategoryTreeParserHook( $top_category, array( 'mode' => 'categories', 'depth' => 10 ) ); |
869 | | - // some string that will hopefully never show up in a category, template |
870 | | - // or field name |
871 | | - $dummy_str = 'REPLACE THIS STRING!'; |
872 | | - $tree = preg_replace( '/(<a class="CategoryTreeLabel.*>)(.*)(<\/a>)/', '<input id="' . $input_id . '" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[' . $dummy_str . ']" value="$2" type="checkbox"> $1$2$3', $tree ); |
873 | | - // replace values one at a time, by an incrementing index - |
874 | | - // inspired by http://bugs.php.net/bug.php?id=11457 |
875 | | - $i = 0; |
876 | | - while ( ( $a = strpos( $tree, $dummy_str ) ) > 0 ) { |
877 | | - $tree = substr( $tree, 0, $a ) . $i++ . substr( $tree, $a + strlen( $dummy_str ) ); |
878 | | - } |
879 | | - // set all checkboxes matching $cur_values to checked |
880 | | - foreach ( $cur_values as $value ) { |
881 | | - $tree = str_replace( "value=\"$value\"", "value=\"$value\" checked=\"checked\"", $tree ); |
882 | | - } |
883 | | - // if it's disabled, set all to disabled |
884 | | - if ( $is_disabled ) { |
885 | | - $tree = str_replace( 'type="checkbox"', 'type="checkbox" disabled', $tree ); |
886 | | - } |
887 | | - $text = '<div style="overflow: auto; padding: 5px; border: 1px #aaaaaa solid; max-height: ' . $height . 'px; width: ' . $width . 'px;">' . $tree . '</div>'; |
888 | | - |
889 | | - $text .= <<<END |
890 | | - <input type="hidden" name="$hidden_input_name" value="1" /> |
891 | | - |
892 | | -END; |
893 | | - |
894 | | - return array( $text, null ); |
895 | | - } |
896 | | -} |
Index: trunk/extensions/SemanticForms/includes/SF_FormField.inc |
— | — | @@ -1,280 +0,0 @@ |
2 | | -<?php |
3 | | -/* |
4 | | - * This class is distinct from SFTemplateField in that it represents a |
5 | | - * template field defined in a form - it contains a SFTemplateField object |
6 | | - * within it (the $template_field variable), along with the other properties |
7 | | - * for that field that are set within the form |
8 | | - */ |
9 | | -class SFFormField { |
10 | | - var $num; |
11 | | - var $template_field; |
12 | | - var $input_type; |
13 | | - var $is_mandatory; |
14 | | - var $is_hidden; |
15 | | - var $is_restricted; |
16 | | - var $possible_values; |
17 | | - // the following fields are not set by the form-creation page |
18 | | - // (though they could be) |
19 | | - var $is_uploadable; |
20 | | - var $field_args; |
21 | | - var $autocomplete_source; |
22 | | - var $autocomplete_field_type; |
23 | | - var $no_autocomplete; |
24 | | - var $part_of_multiple; |
25 | | - // somewhat of a hack - these two fields are for a field in a specific |
26 | | - // representation of a form, not the form definition; ideally these |
27 | | - // should be contained in a third 'field' class, called something like |
28 | | - // SFFormInstanceField, that holds these fields plus an instance of |
29 | | - // SFFormField. Too much work? |
30 | | - var $input_name; |
31 | | - var $is_disabled; |
32 | | - |
33 | | - static function create( $num, $template_field ) { |
34 | | - $f = new SFFormField(); |
35 | | - $f->num = $num; |
36 | | - $f->template_field = $template_field; |
37 | | - $f->input_type = ""; |
38 | | - $f->is_mandatory = false; |
39 | | - $f->is_hidden = false; |
40 | | - $f->is_restricted = false; |
41 | | - $f->is_uploadable = false; |
42 | | - $f->possible_values = null; |
43 | | - return $f; |
44 | | - } |
45 | | - |
46 | | - static function createFromDefinition( $field_name, $input_name, $is_mandatory, $is_hidden, $is_uploadable, $possible_values, $is_disabled, $is_list, $input_type, $field_args, $all_fields, $strict_parsing ) { |
47 | | - // see if this field matches one of the fields defined for this |
48 | | - // template - if it is, use all available information about |
49 | | - // that field; if it's not, either include it in the form or |
50 | | - // not, depending on whether the template has a 'strict' |
51 | | - // setting in the form definition |
52 | | - $the_field = null; |
53 | | - foreach ( $all_fields as $cur_field ) { |
54 | | - if ( $field_name == $cur_field->field_name ) { |
55 | | - $the_field = $cur_field; |
56 | | - break; |
57 | | - } |
58 | | - } |
59 | | - if ( $the_field == null ) { |
60 | | - if ( $strict_parsing ) { |
61 | | - $dummy_ff = new SFFormField(); |
62 | | - $dummy_ff->template_field = new SFTemplateField(); |
63 | | - $dummy_ff->is_list = false; |
64 | | - $dummy_ff->field_args = array(); |
65 | | - return $dummy_ff; |
66 | | - } |
67 | | - $the_field = new SFTemplateField(); |
68 | | - } |
69 | | - |
70 | | - // create an SFFormField object, containing this field as well |
71 | | - // as settings from the form definition file |
72 | | - $f = new SFFormField(); |
73 | | - $f->template_field = $the_field; |
74 | | - $f->is_mandatory = $is_mandatory; |
75 | | - $f->is_hidden = $is_hidden; |
76 | | - $f->is_uploadable = $is_uploadable; |
77 | | - $f->possible_values = $possible_values; |
78 | | - $f->input_type = $input_type; |
79 | | - $f->field_args = $field_args; |
80 | | - $f->input_name = $input_name; |
81 | | - $f->is_disabled = $is_disabled; |
82 | | - $f->is_list = $is_list; |
83 | | - return $f; |
84 | | - } |
85 | | - |
86 | | - /** |
87 | | - * Get the set of possible form input types for either a specific |
88 | | - * SMW property type or a list of such types |
89 | | - */ |
90 | | - function possibleInputTypes( $semantic_type, $is_list ) { |
91 | | - // first, get the list of field types, to determine which one this is |
92 | | - global $smwgContLang; |
93 | | - $datatypeLabels = $smwgContLang->getDatatypeLabels(); |
94 | | - $string_type = $datatypeLabels['_str']; |
95 | | - $text_type = $datatypeLabels['_txt']; |
96 | | - // type introduced in SMW 1.2 |
97 | | - $code_type = array_key_exists( '_cod', $datatypeLabels ) ? $datatypeLabels['_cod'] : 'code'; |
98 | | - $url_type = $datatypeLabels['_uri']; |
99 | | - $email_type = $datatypeLabels['_ema']; |
100 | | - $number_type = $datatypeLabels['_num']; |
101 | | - $bool_type = $datatypeLabels['_boo']; |
102 | | - $date_type = $datatypeLabels['_dat']; |
103 | | - $enum_type = 'enumeration'; // not a real type |
104 | | - $page_type = $datatypeLabels['_wpg']; |
105 | | - |
106 | | - // then, return the array of possible input types, depending on |
107 | | - // the field type and whether this field will contain multiple |
108 | | - // values |
109 | | - if ( $semantic_type == $string_type || |
110 | | - $semantic_type == $number_type || |
111 | | - $semantic_type == $url_type || |
112 | | - $semantic_type == $email_type ) { |
113 | | - if ( $is_list ) { |
114 | | - return array( 'text', 'textarea', 'categories' ); |
115 | | - } else { |
116 | | - return array( 'text', 'category' ); |
117 | | - } |
118 | | - } elseif ( $semantic_type == $text_type || $semantic_type == $code_type ) { |
119 | | - return array( 'textarea' ); |
120 | | - } elseif ( $semantic_type == $bool_type ) { |
121 | | - return array( 'checkbox' ); |
122 | | - } elseif ( $semantic_type == $date_type ) { |
123 | | - return array( 'date', 'datetime', 'datetime with timezone', 'year' ); |
124 | | - } elseif ( $semantic_type == $enum_type ) { |
125 | | - if ( $is_list ) { |
126 | | - return array( 'checkboxes', 'listbox' ); |
127 | | - } else { |
128 | | - return array( 'dropdown', 'radiobutton' ); |
129 | | - } |
130 | | - } elseif ( $semantic_type == $page_type ) { |
131 | | - if ( $is_list ) { |
132 | | - return array( 'text', 'textarea' ); |
133 | | - } else { |
134 | | - return array( 'text' ); |
135 | | - } |
136 | | - } else { // blank or an unknown type |
137 | | - return array( 'text', 'textarea', 'checkbox', 'date', 'datetime', 'datetime with timezone', 'category', 'categories' ); |
138 | | - } |
139 | | - } |
140 | | - |
141 | | - function inputTypeDropdownHTML( $dropdown_name, $possible_input_types, $cur_input_type ) { |
142 | | - // create the dropdown HTML for a list of possible input types |
143 | | - $text = " <select name=\"$dropdown_name\">\n"; |
144 | | - foreach ( $possible_input_types as $i => $input_type ) { |
145 | | - if ( $i == 0 ) { |
146 | | - $text .= " <option value=\"\">$input_type " . |
147 | | - wfMsg( 'sf_createform_inputtypedefault' ) . "</option>\n"; |
148 | | - } else { |
149 | | - $selected_str = ( $cur_input_type == $input_type ) ? "selected" : ""; |
150 | | - $text .= " <option value=\"$input_type\" $selected_str>$input_type</option>\n"; |
151 | | - } |
152 | | - } |
153 | | - $text .= " </select>\n"; |
154 | | - return $text; |
155 | | - } |
156 | | - |
157 | | - function creationHTML( $template_num ) { |
158 | | - $field_form_text = $template_num . "_" . $this->num; |
159 | | - $template_field = $this->template_field; |
160 | | - $text = '<h3>' . wfMsg( 'sf_createform_field' ) . " '" . $template_field->field_name . "'</h3>\n"; |
161 | | - $prop_link_text = SFUtils::linkText( SMW_NS_PROPERTY, $template_field->semantic_property ); |
162 | | - // TODO - remove this probably-unnecessary check? |
163 | | - if ( $template_field->semantic_property == "" ) { |
164 | | - // print nothing if there's no semantic field |
165 | | - } elseif ( $template_field->field_type == "" ) { |
166 | | - $text .= '<p>' . wfMsg( 'sf_createform_fieldpropunknowntype', $prop_link_text ) . "</p>\n"; |
167 | | - } elseif ( $template_field->is_list ) { |
168 | | - $text .= '<p>' . wfMsg( 'sf_createform_fieldproplist', $prop_link_text, |
169 | | - SFUtils::linkText( SMW_NS_TYPE, $template_field->field_type ) ) . "</p>\n"; |
170 | | - } else { |
171 | | - $text .= '<p>' . wfMsg( 'sf_createform_fieldprop', $prop_link_text, |
172 | | - SFUtils::linkText( SMW_NS_TYPE, $template_field->field_type ) ) . "</p>\n"; |
173 | | - } |
174 | | - // if it's not a semantic field - don't add any text |
175 | | - $form_label_text = wfMsg( 'sf_createform_formlabel' ); |
176 | | - $field_label = $template_field->label; |
177 | | - $input_type_text = wfMsg( 'sf_createform_inputtype' ); |
178 | | - $text .= <<<END |
179 | | - <p>$form_label_text <input type="text" name="label_$field_form_text" size=20 value="$field_label" /> |
180 | | - $input_type_text |
181 | | - |
182 | | -END; |
183 | | - $possible_input_types = $this->possibleInputTypes( $template_field->field_type, $template_field->is_list ); |
184 | | - if ( count( $possible_input_types ) > 1 ) { |
185 | | - $text .= $this->inputTypeDropdownHTML( "input_type_$field_form_text", $possible_input_types, $template_field->input_type ); |
186 | | - } else { |
187 | | - $text .= $possible_input_types[0]; |
188 | | - } |
189 | | - $mandatory_checked_str = ( $this->is_mandatory ) ? "checked" : ""; |
190 | | - $mandatory_text = wfMsg( 'sf_createform_mandatory' ); |
191 | | - $hidden_checked_str = ( $this->is_hidden ) ? "checked" : ""; |
192 | | - $hidden_text = wfMsg( 'sf_createform_hidden' ); |
193 | | - $restricted_checked_str = ( $this->is_restricted ) ? "checked" : ""; |
194 | | - $restricted_text = wfMsg( 'sf_createform_restricted' ); |
195 | | - $text .= <<<END |
196 | | - </p> |
197 | | - <p> |
198 | | - <input type="checkbox" name="mandatory_$field_form_text" value="mandatory" $mandatory_checked_str /> $mandatory_text |
199 | | - <input type="checkbox" name="hidden_$field_form_text" value="hidden" $hidden_checked_str /> $hidden_text |
200 | | - <input type="checkbox" name="restricted_$field_form_text" value="restricted" $restricted_checked_str /> $restricted_text</p> |
201 | | - <hr> |
202 | | - |
203 | | -END; |
204 | | - return $text; |
205 | | - } |
206 | | - |
207 | | - // for now, HTML of an individual field depends on whether or not it's |
208 | | - // part of multiple-instance template; this may change if handling of |
209 | | - // such templates in form definitions gets more sophisticated |
210 | | - function createMarkup( $part_of_multiple, $is_last_field_in_template ) { |
211 | | - $text = ""; |
212 | | - if ( $this->template_field->label != "" ) { |
213 | | - if ( $part_of_multiple ) { |
214 | | - $text .= "'''" . $this->template_field->label . ":''' "; |
215 | | - } else { |
216 | | - $text .= "! " . $this->template_field->label . ":\n"; |
217 | | - } |
218 | | - } |
219 | | - if ( ! $part_of_multiple ) { $text .= "| "; } |
220 | | - $text .= "{{{field|" . $this->template_field->field_name; |
221 | | - if ( isset( $this->template_field->input_type ) && |
222 | | - $this->template_field->input_type != null ) { |
223 | | - $text .= "|input type=" . $this->template_field->input_type; |
224 | | - } |
225 | | - if ( $this->is_mandatory ) { |
226 | | - $text .= "|mandatory"; |
227 | | - } elseif ( $this->is_hidden ) { |
228 | | - $text .= "|hidden"; |
229 | | - } elseif ( $this->is_restricted ) { |
230 | | - $text .= "|restricted"; |
231 | | - } |
232 | | - $text .= "}}}\n"; |
233 | | - if ( $part_of_multiple ) { |
234 | | - $text .= "\n"; |
235 | | - } elseif ( ! $is_last_field_in_template ) { |
236 | | - $text .= "|-\n"; |
237 | | - } |
238 | | - return $text; |
239 | | - } |
240 | | - |
241 | | - /* |
242 | | - * Since Semantic Forms uses a hook system for the functions that |
243 | | - * create HTML inputs, most arguments are contained in the "$other_args" |
244 | | - * array - create this array, using the attributes of this form |
245 | | - * field and the template field it corresponds to, if any |
246 | | - */ |
247 | | - function getArgumentsForInputCall( $default_args = null ) { |
248 | | - // start with the arguments array already defined |
249 | | - $other_args = $this->field_args; |
250 | | - // a value defined for the form field should always supersede |
251 | | - // the coresponding value for the template field |
252 | | - if ( $this->possible_values != null ) |
253 | | - $other_args['possible_values'] = $this->possible_values; |
254 | | - else { |
255 | | - $other_args['possible_values'] = $this->template_field->possible_values; |
256 | | - $other_args['value_labels'] = $this->template_field->value_labels; |
257 | | - } |
258 | | - $other_args['is_list'] = ( $this->is_list || $this->template_field->is_list ); |
259 | | - if ( $this->template_field->semantic_property != '' && ! array_key_exists( 'semantic_property', $other_args ) ) |
260 | | - $other_args['semantic_property'] = $this->template_field->semantic_property; |
261 | | - // if autocompletion hasn't already been hardcoded in the form, |
262 | | - // and it's a property of type page, or a property of another |
263 | | - // type with 'autocomplete' specified, set the necessary |
264 | | - // parameters |
265 | | - if ( ! array_key_exists( 'autocompletion source', $other_args ) ) { |
266 | | - if ( $this->template_field->propertyIsOfType( '_wpg' ) ) { |
267 | | - $other_args['autocompletion source'] = $this->template_field->semantic_property; |
268 | | - $other_args['autocomplete field type'] = 'relation'; |
269 | | - } elseif ( array_key_exists( 'autocomplete', $other_args ) || array_key_exists( 'remote autocompletion', $other_args ) ) { |
270 | | - $other_args['autocompletion source'] = $this->template_field->semantic_property; |
271 | | - $other_args['autocomplete field type'] = 'attribute'; |
272 | | - } |
273 | | - } |
274 | | - // now merge in the default values set by SFFormPrinter, if |
275 | | - // there were any - put the default values first, so that if |
276 | | - // there's a conflict they'll be overridden |
277 | | - if ( $default_args != null ) |
278 | | - $other_args = array_merge( $default_args, $other_args ); |
279 | | - return $other_args; |
280 | | - } |
281 | | -} |
Index: trunk/extensions/SemanticForms/includes/SF_FormPrinter.inc |
— | — | @@ -1,1409 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Handles the creation and running of a user-created form. |
5 | | - * |
6 | | - * @author Yaron Koren |
7 | | - * @author Nils Oppermann |
8 | | - * @author Jeffrey Stuckman |
9 | | - * @author Harold Solbrig |
10 | | - * @author Daniel Hansch |
11 | | - */ |
12 | | - |
13 | | -class SFFormPrinter { |
14 | | - |
15 | | - var $mSemanticTypeHooks; |
16 | | - var $mInputTypeHooks; |
17 | | - var $standardInputsIncluded; |
18 | | - var $mPageTitle; |
19 | | - |
20 | | - function SFFormPrinter() { |
21 | | - global $smwgContLang; |
22 | | - |
23 | | - // initialize the set of hooks for the entry-field functions to call for |
24 | | - // fields of both a specific semantic "type" and a defined "input type" |
25 | | - // in the form definition |
26 | | - $this->mSemanticTypeHooks = array(); |
27 | | - if ( $smwgContLang != null ) { |
28 | | - $datatypeLabels = $smwgContLang->getDatatypeLabels(); |
29 | | - $string_type = $datatypeLabels['_str']; |
30 | | - $text_type = $datatypeLabels['_txt']; |
31 | | - // type introduced in SMW 1.2 |
32 | | - if ( array_key_exists( '_cod', $datatypeLabels ) ) |
33 | | - $code_type = $datatypeLabels['_cod']; |
34 | | - else |
35 | | - $code_type = 'code'; |
36 | | - $url_type = $datatypeLabels['_uri']; |
37 | | - $email_type = $datatypeLabels['_ema']; |
38 | | - $number_type = $datatypeLabels['_num']; |
39 | | - $bool_type = $datatypeLabels['_boo']; |
40 | | - $date_type = $datatypeLabels['_dat']; |
41 | | - $enum_type = 'enumeration'; // not a real type |
42 | | - $page_type = $datatypeLabels['_wpg']; |
43 | | - $this->setSemanticTypeHook( $string_type, false, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'string' ) ); |
44 | | - $this->setSemanticTypeHook( $string_type, true, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'string', 'is_list' => 'true', 'size' => '100' ) ); |
45 | | - $this->setSemanticTypeHook( $text_type, false, array( 'SFFormInputs', 'textAreaHTML' ), array() ); |
46 | | - $this->setSemanticTypeHook( $code_type, false, array( 'SFFormInputs', 'textAreaHTML' ), array() ); |
47 | | - $this->setSemanticTypeHook( $url_type, false, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'URL' ) ); |
48 | | - $this->setSemanticTypeHook( $email_type, false, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'email' ) ); |
49 | | - $this->setSemanticTypeHook( $number_type, false, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'number' ) ); |
50 | | - $this->setSemanticTypeHook( $bool_type, false, array( 'SFFormInputs', 'checkboxHTML' ), array() ); |
51 | | - $this->setSemanticTypeHook( $date_type, false, array( 'SFFormInputs', 'dateEntryHTML' ), array() ); |
52 | | - $this->setSemanticTypeHook( $enum_type, false, array( 'SFFormInputs', 'dropdownHTML' ), array() ); |
53 | | - $this->setSemanticTypeHook( $enum_type, true, array( 'SFFormInputs', 'checkboxesHTML' ), array() ); |
54 | | - $this->setSemanticTypeHook( $page_type, false, array( 'SFFormInputs', 'textInputWithAutocompleteHTML' ), array( 'field_type' => 'page' ) ); |
55 | | - $this->setSemanticTypeHook( $page_type, true, array( 'SFFormInputs', 'textInputWithAutocompleteHTML' ), array( 'field_type' => 'page', 'size' => '100', 'is_list' => 'true' ) ); |
56 | | - } |
57 | | - $this->mInputTypeHooks = array(); |
58 | | - $this->setInputTypeHook( 'text', array( 'SFFormInputs', 'textEntryHTML' ), array() ); |
59 | | - $this->setInputTypeHook( 'textarea', array( 'SFFormInputs', 'textAreaHTML' ), array() ); |
60 | | - $this->setInputTypeHook( 'date', array( 'SFFormInputs', 'dateEntryHTML' ), array() ); |
61 | | - $this->setInputTypeHook( 'datetime', array( 'SFFormInputs', 'dateTimeEntryHTML' ), array( 'include_timezone' => false ) ); |
62 | | - $this->setInputTypeHook( 'datetime with timezone', array( 'SFFormInputs', 'dateTimeEntryHTML' ), array( 'include_timezone' => true ) ); |
63 | | - $this->setInputTypeHook( 'year', array( 'SFFormInputs', 'textEntryHTML' ), array( 'size' => 4 ) ); |
64 | | - $this->setInputTypeHook( 'checkbox', array( 'SFFormInputs', 'checkboxHTML' ), array() ); |
65 | | - $this->setInputTypeHook( 'radiobutton', array( 'SFFormInputs', 'radioButtonHTML' ), array() ); |
66 | | - $this->setInputTypeHook( 'checkboxes', array( 'SFFormInputs', 'checkboxesHTML' ), array() ); |
67 | | - $this->setInputTypeHook( 'listbox', array( 'SFFormInputs', 'listboxHTML' ), array() ); |
68 | | - $this->setInputTypeHook( 'category', array( 'SFFormInputs', 'categoryHTML' ), array() ); |
69 | | - $this->setInputTypeHook( 'categories', array( 'SFFormInputs', 'categoriesHTML' ), array() ); |
70 | | - |
71 | | - // initialize other variables |
72 | | - $this->standardInputsIncluded = false; |
73 | | - } |
74 | | - |
75 | | - function setSemanticTypeHook( $type, $is_list, $function_name, $default_args ) { |
76 | | - $this->mSemanticTypeHooks[$type][$is_list] = array( $function_name, $default_args ); |
77 | | - } |
78 | | - |
79 | | - function setInputTypeHook( $input_type, $function_name, $default_args ) { |
80 | | - $this->mInputTypeHooks[$input_type] = array( $function_name, $default_args ); |
81 | | - } |
82 | | - |
83 | | - |
84 | | - /** |
85 | | - * Show the set of previous deletions for the page being added. |
86 | | - * This function is copied almost exactly from EditPage::showDeletionLog() - |
87 | | - * unfortunately, neither that function nor Article::showDeletionLog() can |
88 | | - * be called from here, since they're both protected |
89 | | - */ |
90 | | - function showDeletionLog( $out ) { |
91 | | - // if MW doesn't have LogEventsList defined, exit immediately |
92 | | - if ( ! class_exists( 'LogEventsList' ) ) |
93 | | - return false; |
94 | | - |
95 | | - global $wgUser; |
96 | | - $loglist = new LogEventsList( $wgUser->getSkin(), $out ); |
97 | | - $pager = new LogPager( $loglist, 'delete', false, $this->mPageTitle->getPrefixedText() ); |
98 | | - $count = $pager->getNumRows(); |
99 | | - if ( $count > 0 ) { |
100 | | - $pager->mLimit = 10; |
101 | | - $out->addHTML( '<div class="mw-warning-with-logexcerpt">' ); |
102 | | - // the message name changed in MW 1.16 |
103 | | - if ( ! wfEmptyMsg( 'moveddeleted-notice', wfMsg( 'moveddeleted-notice' ) ) ) |
104 | | - $out->addWikiMsg( 'moveddeleted-notice' ); |
105 | | - else |
106 | | - $out->addWikiMsg( 'recreate-deleted-warn' ); |
107 | | - $out->addHTML( |
108 | | - $loglist->beginLogEventsList() . |
109 | | - $pager->getBody() . |
110 | | - $loglist->endLogEventsList() |
111 | | - ); |
112 | | - if ( $count > 10 ) { |
113 | | - $out->addHTML( $wgUser->getSkin()->link( |
114 | | - SpecialPage::getTitleFor( 'Log' ), |
115 | | - wfMsgHtml( 'deletelog-fulllog' ), |
116 | | - array(), |
117 | | - array( |
118 | | - 'type' => 'delete', |
119 | | - 'page' => $this->mPageTitle->getPrefixedText() ) ) ); |
120 | | - } |
121 | | - $out->addHTML( '</div>' ); |
122 | | - return true; |
123 | | - } |
124 | | - |
125 | | - return false; |
126 | | - } |
127 | | - |
128 | | - function formHTML( $form_def, $form_submitted, $source_is_page, $form_id = null, $existing_page_content = null, $page_name = null, $page_name_formula = null, $is_query = false, $embedded = false ) { |
129 | | - global $wgRequest, $wgUser, $wgParser; |
130 | | - global $sfgTabIndex; // used to represent the current tab index in the form |
131 | | - global $sfgFieldNum; // used for setting various HTML IDs |
132 | | - global $sfgJSValidationCalls; // array of Javascript calls to determine if page can be saved |
133 | | - |
134 | | - // initialize some variables |
135 | | - $sfgTabIndex = 1; |
136 | | - $sfgFieldNum = 1; |
137 | | - $source_page_matches_this_form = false; |
138 | | - $form_page_title = NULL; |
139 | | - $generated_page_name = $page_name_formula; |
140 | | - // $form_is_partial is true if: |
141 | | - // (a) 'partial' == 1 in the arguments |
142 | | - // (b) 'partial form' is found in the form definition |
143 | | - // in the latter case, it may remain false until close to the end of |
144 | | - // the parsing, so we have to assume that it will become a possibility |
145 | | - $form_is_partial = false; |
146 | | - $new_text = ""; |
147 | | - // flag for placing "<onlyinclude>" tags in form output |
148 | | - $onlyinclude_free_text = false; |
149 | | - |
150 | | - // if we have existing content and we're not in an active replacement |
151 | | - // situation, preserve the original content. We do this because we want |
152 | | - // to pass the original content on IF this is a partial form |
153 | | - // TODO: A better approach here would be to pass the revision id of the |
154 | | - // existing page content through the replace value, which would |
155 | | - // minimize the html traffic and would allow us to do a concurrent |
156 | | - // update check. For now, we pass it through the hidden text field... |
157 | | - |
158 | | - if ( ! $wgRequest->getCheck( 'partial' ) ) { |
159 | | - $original_page_content = $existing_page_content; |
160 | | - } else { |
161 | | - $original_page_content = null; |
162 | | - if ( $wgRequest->getCheck( 'free_text' ) ) { |
163 | | - $existing_page_content = $wgRequest->getVal( 'free_text' ); |
164 | | - $form_is_partial = true; |
165 | | - } |
166 | | - } |
167 | | - |
168 | | - // disable all form elements if user doesn't have edit permission - |
169 | | - // two different checks are needed, because editing permissions can be |
170 | | - // set in different ways |
171 | | - // HACK - sometimes we don't know the page name in advance, but we still |
172 | | - // need to set a title here for testing permissions |
173 | | - if ( $page_name == '' ) |
174 | | - $this->mPageTitle = Title::newFromText( |
175 | | - $wgRequest->getVal( 'namespace' ) . ":Semantic Forms permissions test" ); |
176 | | - else |
177 | | - $this->mPageTitle = Title::newFromText( $page_name ); |
178 | | - global $wgOut; |
179 | | - // show previous set of deletions for this page, if it's been deleted before |
180 | | - if ( ! $form_submitted && ! $this->mPageTitle->exists() ) { |
181 | | - $this->showDeletionLog( $wgOut ); |
182 | | - } |
183 | | - $user_can_edit_page = ( $wgUser->isAllowed( 'edit' ) && $this->mPageTitle->userCan( 'edit' ) ); |
184 | | - wfRunHooks( 'sfUserCanEditPage', array( &$user_can_edit_page ) ); |
185 | | - if ( $user_can_edit_page || $is_query ) { |
186 | | - $form_is_disabled = false; |
187 | | - $form_text = ""; |
188 | | - // show "Your IP address will be recorded" warning if user is |
189 | | - // anonymous, and it's not a query - |
190 | | - // wikitext for bolding has to be replaced with HTML |
191 | | - if ( $wgUser->isAnon() && ! $is_query ) { |
192 | | - $anon_edit_warning = preg_replace( "/'''(.*)'''/", "<strong>$1</strong>", wfMsg( 'anoneditwarning' ) ); |
193 | | - $form_text .= "<p>$anon_edit_warning</p>\n"; |
194 | | - } |
195 | | - } else { |
196 | | - $form_is_disabled = true; |
197 | | - // display a message to the user explaining why they can't edit the |
198 | | - // page - borrowed heavily from EditPage.php |
199 | | - if ( $wgUser->isAnon() ) { |
200 | | - $skin = $wgUser->getSkin(); |
201 | | - $loginTitle = SpecialPage::getTitleFor( 'Userlogin' ); |
202 | | - $loginLink = $skin->makeKnownLinkObj( $loginTitle, wfMsgHtml( 'loginreqlink' ) ); |
203 | | - $form_text = wfMsgWikiHtml( 'whitelistedittext', $loginLink ); |
204 | | - } else { |
205 | | - $form_text = wfMsg( 'protectedpagetext' ); |
206 | | - } |
207 | | - } |
208 | | - $javascript_text = ""; |
209 | | - $sfgJSValidationCalls = array(); |
210 | | - $fields_javascript_text = ""; |
211 | | - |
212 | | - // Remove <noinclude> sections and <includeonly> tags from form definition |
213 | | - $form_def = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $form_def ); |
214 | | - $form_def = strtr( $form_def, array( '<includeonly>' => '', '</includeonly>' => '' ) ); |
215 | | - |
216 | | - // parse wiki-text |
217 | | - // add '<nowiki>' tags around every triple-bracketed form definition |
218 | | - // element, so that the wiki parser won't touch it - the parser will |
219 | | - // remove the '<nowiki>' tags, leaving us with what we need |
220 | | - $form_def = "__NOEDITSECTION__" . strtr( $form_def, array( '{{{' => '<nowiki>{{{', '}}}' => '}}}</nowiki>' ) ); |
221 | | - $old_strip_state = $wgParser->mStripState; |
222 | | - $wgParser->mStripState = new StripState(); |
223 | | - $wgParser->mOptions = new ParserOptions(); |
224 | | - $wgParser->mOptions->initialiseFromUser( $wgUser ); |
225 | | - |
226 | | - // get the form definition from the cache, if we're using caching and it's |
227 | | - // there |
228 | | - $got_form_def_from_cache = false; |
229 | | - global $sfgCacheFormDefinitions; |
230 | | - if ( $sfgCacheFormDefinitions && ! is_null( $form_id ) ) { |
231 | | - $db = wfGetDB( DB_MASTER ); |
232 | | - $res = $db->select( 'page_props', 'pp_value', "pp_propname = 'formdefinition' AND pp_page = '$form_id'" ); |
233 | | - if ( $res->numRows() > 0 ) { |
234 | | - $form_def = $res->fetchObject()->pp_value; |
235 | | - $got_form_def_from_cache = true; |
236 | | - } |
237 | | - } |
238 | | - // otherwise, parse it |
239 | | - if ( ! $got_form_def_from_cache ) |
240 | | - $form_def = $wgParser->parse( $form_def, $this->mPageTitle, $wgParser->mOptions )->getText(); |
241 | | - $wgParser->mStripState = $old_strip_state; |
242 | | - |
243 | | - // turn form definition file into an array of sections, one for each |
244 | | - // template definition (plus the first section) |
245 | | - $form_def_sections = array(); |
246 | | - $start_position = 0; |
247 | | - $section_start = 0; |
248 | | - $free_text_was_included = false; |
249 | | - $free_text_preload_page = null; |
250 | | - $free_text_components = array(); |
251 | | - $all_values_for_template = array(); |
252 | | - // unencode and HTML-encoded representations of curly brackets and |
253 | | - // pipes - this is a hack to allow for forms to include templates |
254 | | - // that themselves contain form elements - the escaping is needed |
255 | | - // to make sure that those elements don't get parsed too early |
256 | | - $form_def = str_replace( array( '{', '|', '}' ), array( '{', '|', '}' ), $form_def ); |
257 | | - // and another hack - replace the 'free text' standard input with |
258 | | - // a field declaration to get it to be handled as a field |
259 | | - $form_def = str_replace( 'standard input|free text', 'field|<freetext>', $form_def ); |
260 | | - while ( $brackets_loc = strpos( $form_def, "{{{", $start_position ) ) { |
261 | | - $brackets_end_loc = strpos( $form_def, "}}}", $brackets_loc ); |
262 | | - $bracketed_string = substr( $form_def, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) ); |
263 | | - $tag_components = explode( '|', $bracketed_string ); |
264 | | - $tag_title = trim( $tag_components[0] ); |
265 | | - if ( $tag_title == 'for template' || $tag_title == 'end template' ) { |
266 | | - // create a section for everything up to here |
267 | | - $section = substr( $form_def, $section_start, $brackets_loc - $section_start ); |
268 | | - $form_def_sections[] = $section; |
269 | | - $section_start = $brackets_loc; |
270 | | - } |
271 | | - $start_position = $brackets_loc + 1; |
272 | | - } // end while |
273 | | - $form_def_sections[] = trim( substr( $form_def, $section_start ) ); |
274 | | - |
275 | | - // cycle through form definition file (and possibly an existing article |
276 | | - // as well), finding template and field declarations and replacing them |
277 | | - // with form elements, either blank or pre-populated, as appropriate |
278 | | - $all_fields = array(); |
279 | | - $data_text = ""; |
280 | | - $template_name = ""; |
281 | | - $allow_multiple = false; |
282 | | - $instance_num = 0; |
283 | | - $all_instances_printed = false; |
284 | | - $strict_parsing = false; |
285 | | - // initialize list of choosers (dropdowns with available templates) |
286 | | - $choosers = array(); |
287 | | - for ( $section_num = 0; $section_num < count( $form_def_sections ); $section_num++ ) { |
288 | | - $tif = new SFTemplateInForm(); |
289 | | - $start_position = 0; |
290 | | - $template_text = ""; |
291 | | - // the append is there to ensure that the original array doesn't get |
292 | | - // modified; is it necessary? |
293 | | - $section = " " . $form_def_sections[$section_num]; |
294 | | - |
295 | | - while ( $brackets_loc = strpos( $section, '{{{', $start_position ) ) { |
296 | | - $brackets_end_loc = strpos( $section, "}}}", $brackets_loc ); |
297 | | - $bracketed_string = substr( $section, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) ); |
298 | | - $tag_components = explode( '|', $bracketed_string ); |
299 | | - $tag_title = trim( $tag_components[0] ); |
300 | | - // ===================================================== |
301 | | - // for template processing |
302 | | - // ===================================================== |
303 | | - if ( $tag_title == 'for template' ) { |
304 | | - $old_template_name = $template_name; |
305 | | - $template_name = trim( $tag_components[1] ); |
306 | | - $tif->template_name = $template_name; |
307 | | - $query_template_name = str_replace( ' ', '_', $template_name ); |
308 | | - // also replace periods with underlines, since that's what |
309 | | - // POST does to strings anyway |
310 | | - $query_template_name = str_replace( '.', '_', $query_template_name ); |
311 | | - $chooser_name = false; |
312 | | - $chooser_caption = false; |
313 | | - // cycle through the other components |
314 | | - for ( $i = 2; $i < count( $tag_components ); $i++ ) { |
315 | | - $component = $tag_components[$i]; |
316 | | - if ( $component == 'multiple' ) $allow_multiple = true; |
317 | | - if ( $component == 'strict' ) $strict_parsing = true; |
318 | | - $sub_components = explode( '=', $component, 2 ); |
319 | | - if ( count( $sub_components ) == 2 ) { |
320 | | - if ( $sub_components[0] == 'label' ) { |
321 | | - $template_label = $sub_components[1]; |
322 | | - } elseif ( $sub_components[0] == 'chooser' ) { |
323 | | - $allow_multiple = true; |
324 | | - $chooser_name = $sub_components[1]; |
325 | | - } elseif ( $sub_components[0] == 'chooser caption' ) { |
326 | | - $chooser_caption = $sub_components[1]; |
327 | | - } |
328 | | - } |
329 | | - } |
330 | | - // if this is the first instance, add the label in the form |
331 | | - if ( ( $old_template_name != $template_name ) && isset( $template_label ) ) { |
332 | | - // add a placeholder to the form text so the fieldset can be |
333 | | - // hidden if chooser support demands it |
334 | | - if ( $chooser_name !== false ) |
335 | | - $form_text .= "<fieldset [[placeholder]] haschooser=true>\n"; |
336 | | - else |
337 | | - $form_text .= "<fieldset>\n"; |
338 | | - $form_text .= "<legend>$template_label</legend>\n"; |
339 | | - } |
340 | | - $template_text .= "{{" . $tif->template_name; |
341 | | - $all_fields = $tif->getAllFields(); |
342 | | - // remove template tag |
343 | | - $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
344 | | - $template_instance_query_values = $wgRequest->getArray( $query_template_name ); |
345 | | - // if we are editing a page, and this template can be found more than |
346 | | - // once in that page, and multiple values are allowed, repeat this |
347 | | - // section |
348 | | - $existing_template_text = null; |
349 | | - if ( $source_is_page || $form_is_partial ) { |
350 | | - // replace underlines with spaces in template name, to allow for |
351 | | - // searching on either |
352 | | - $search_template_str = str_replace( '_', ' ', $tif->template_name ); |
353 | | - $preg_match_template_str = str_replace( |
354 | | - array( '/', '(', ')' ), |
355 | | - array( '\/', '\(', '\)' ), |
356 | | - $search_template_str ); |
357 | | - $found_instance = preg_match( '/{{' . $preg_match_template_str . '\s*[\|}]/i', str_replace( '_', ' ', $existing_page_content ) ); |
358 | | - if ( $allow_multiple ) { |
359 | | - // find instances of this template in the page - |
360 | | - // if there's at least one, re-parse this section of the |
361 | | - // definition form for the subsequent template instances in |
362 | | - // this page; if there's none, don't include fields at all. |
363 | | - // there has to be a more efficient way to handle multiple |
364 | | - // instances of templates, one that doesn't involve re-parsing |
365 | | - // the same tags, but I don't know what it is. |
366 | | - if ( $found_instance ) { |
367 | | - $instance_num++; |
368 | | - } else { |
369 | | - $all_instances_printed = true; |
370 | | - } |
371 | | - } |
372 | | - // get the first instance of this template on the page being edited, |
373 | | - // even if there are more |
374 | | - if ( $found_instance && ( $start_char = stripos( str_replace( '_', ' ', $existing_page_content ), '{{' . $search_template_str ) ) !== false ) { |
375 | | - $fields_start_char = $start_char + 2 + strlen( $search_template_str ); |
376 | | - // skip ahead to the first real character |
377 | | - while ( in_array( $existing_page_content[$fields_start_char], array( ' ', '\n', '|' ) ) ) { |
378 | | - $fields_start_char++; |
379 | | - } |
380 | | - $template_contents = array( '0' => '' ); |
381 | | - // cycle through template call, splitting it up by pipes ('|'), |
382 | | - // except when that pipe is part of a piped link |
383 | | - $field = ""; |
384 | | - $uncompleted_square_brackets = 0; |
385 | | - $uncompleted_curly_brackets = 2; |
386 | | - $template_ended = false; |
387 | | - for ( $i = $fields_start_char; ! $template_ended && ( $i < strlen( $existing_page_content ) ); $i++ ) { |
388 | | - $c = $existing_page_content[$i]; |
389 | | - if ( $c == '[' ) { |
390 | | - $uncompleted_square_brackets++; |
391 | | - } elseif ( $c == ']' && $uncompleted_square_brackets > 0 ) { |
392 | | - $uncompleted_square_brackets--; |
393 | | - } elseif ( $c == '{' ) { |
394 | | - $uncompleted_curly_brackets++; |
395 | | - } elseif ( $c == '}' && $uncompleted_curly_brackets > 0 ) { |
396 | | - $uncompleted_curly_brackets--; |
397 | | - } |
398 | | - // handle an end to a field and/or template declaration |
399 | | - $template_ended = ( $uncompleted_curly_brackets == 0 && $uncompleted_square_brackets == 0 ); |
400 | | - $field_ended = ( $c == '|' && $uncompleted_square_brackets == 0 && $uncompleted_curly_brackets <= 2 ); |
401 | | - if ( $template_ended || $field_ended ) { |
402 | | - // if this was the last character in the template, remove |
403 | | - // the closing curly brackets |
404 | | - if ( $template_ended ) { |
405 | | - $field = substr( $field, 0, - 1 ); |
406 | | - } |
407 | | - // either there's an equals sign near the beginning or not - |
408 | | - // handling is similar in either way; if there's no equals |
409 | | - // sign, the index of this field becomes the key |
410 | | - $sub_fields = explode( '=', $field, 2 ); |
411 | | - if ( count( $sub_fields ) > 1 ) { |
412 | | - $template_contents[trim( $sub_fields[0] )] = trim( $sub_fields[1] ); |
413 | | - } else { |
414 | | - $template_contents[] = trim( $sub_fields[0] ); |
415 | | - } |
416 | | - $field = ''; |
417 | | - } else { |
418 | | - $field .= $c; |
419 | | - } |
420 | | - } |
421 | | - $existing_template_text = substr( $existing_page_content, $start_char, $i - $start_char ); |
422 | | - // now remove this template from the text being edited |
423 | | - // if this is a partial form, establish a new insertion point |
424 | | - if ( $existing_page_content && $form_is_partial && $wgRequest->getCheck( 'partial' ) ) { |
425 | | - // if something already exists, set the new insertion point |
426 | | - // to its position; otherwise just let it lie |
427 | | - if ( strpos( $existing_page_content, $existing_template_text ) !== false ) { |
428 | | - $existing_page_content = str_replace( '{{{insertionpoint}}}', '', $existing_page_content ); |
429 | | - $existing_page_content = str_replace( $existing_template_text, '{{{insertionpoint}}}', $existing_page_content ); |
430 | | - } |
431 | | - } else { |
432 | | - $existing_page_content = str_replace( $existing_template_text, '', $existing_page_content ); |
433 | | - } |
434 | | - // if this is not a multiple-instance template, and we've found |
435 | | - // a match in the source page, there's a good chance that this |
436 | | - // page was created with this form - note that, so we don't |
437 | | - // send the user a warning |
438 | | - // (multiple-instance templates have a greater chance of |
439 | | - // getting repeated from one form to the next) |
440 | | - // - on second thought, allow even the presence of multiple- |
441 | | - // instance templates to validate that this is the correct |
442 | | - // form: the problem is that some forms contain *only* mutliple- |
443 | | - // instance templates |
444 | | - // if (! $allow_multiple) { |
445 | | - $source_page_matches_this_form = true; |
446 | | - // } |
447 | | - } |
448 | | - } |
449 | | - // if the input is from the form (meaning the user has hit one |
450 | | - // of the bottom row of buttons), and we're dealing with a |
451 | | - // multiple template, get the values for this instance of this |
452 | | - // template, then delete them from the array, so we can get the |
453 | | - // next group next time - the next() command for arrays doesn't |
454 | | - // seem to work here |
455 | | - if ( ( ! $source_is_page ) && $allow_multiple && $wgRequest ) { |
456 | | - $all_instances_printed = true; |
457 | | - if ( $old_template_name != $template_name ) { |
458 | | - $all_values_for_template = $wgRequest->getArray( $query_template_name ); |
459 | | - } |
460 | | - if ( $all_values_for_template ) { |
461 | | - $cur_key = key( $all_values_for_template ); |
462 | | - // skip the input coming in from the "starter" div |
463 | | - if ( $cur_key == 'num' ) { |
464 | | - unset( $all_values_for_template[$cur_key] ); |
465 | | - $cur_key = key( $all_values_for_template ); |
466 | | - } |
467 | | - if ( $template_instance_query_values = current( $all_values_for_template ) ) { |
468 | | - $all_instances_printed = false; |
469 | | - unset( $all_values_for_template[$cur_key] ); |
470 | | - } |
471 | | - } |
472 | | - } |
473 | | - // ===================================================== |
474 | | - // end template processing |
475 | | - // ===================================================== |
476 | | - } elseif ( $tag_title == 'end template' ) { |
477 | | - if ( $source_is_page ) { |
478 | | - // add any unhandled template fields in the page as hidden variables |
479 | | - if ( isset( $template_contents ) ) |
480 | | - $form_text .= SFFormUtils::unhandledFieldsHTML( $template_contents ); |
481 | | - } |
482 | | - // remove this tag, reset some variables, and close off form HTML tag |
483 | | - $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
484 | | - $template_name = null; |
485 | | - if ( isset( $template_label ) ) { |
486 | | - $form_text .= "</fieldset>\n"; |
487 | | - unset ( $template_label ); |
488 | | - } |
489 | | - $allow_multiple = false; |
490 | | - $all_instances_printed = false; |
491 | | - $instance_num = 0; |
492 | | - // if the hiding placeholder is still around, this fieldset should |
493 | | - // be hidden because it is empty and choosers are being used. So, |
494 | | - // hide it. |
495 | | - $form_text = str_replace( "[[placeholder]]", "style='display:none'", $form_text ); |
496 | | - // ===================================================== |
497 | | - // field processing |
498 | | - // ===================================================== |
499 | | - } elseif ( $tag_title == 'field' ) { |
500 | | - $field_name = trim( $tag_components[1] ); |
501 | | - // cycle through the other components |
502 | | - $is_mandatory = false; |
503 | | - $is_hidden = false; |
504 | | - $is_restricted = false; |
505 | | - $is_uploadable = false; |
506 | | - $is_list = false; |
507 | | - $input_type = null; |
508 | | - $field_args = array(); |
509 | | - $show_on_select = array(); |
510 | | - $default_value = ""; |
511 | | - $possible_values = null; |
512 | | - $semantic_property = null; |
513 | | - $preload_page = null; |
514 | | - for ( $i = 2; $i < count( $tag_components ); $i++ ) { |
515 | | - $component = trim( $tag_components[$i] ); |
516 | | - if ( $component == 'mandatory' ) { |
517 | | - $is_mandatory = true; |
518 | | - } elseif ( $component == 'hidden' ) { |
519 | | - $is_hidden = true; |
520 | | - } elseif ( $component == 'restricted' ) { |
521 | | - $is_restricted = true; |
522 | | - } elseif ( $component == 'uploadable' ) { |
523 | | - $field_args['is_uploadable'] = true; |
524 | | - } elseif ( $component == 'list' ) { |
525 | | - $is_list = true; |
526 | | - } elseif ( $component == 'autocomplete' ) { |
527 | | - $field_args['autocomplete'] = true; |
528 | | - } elseif ( $component == 'no autocomplete' ) { |
529 | | - $field_args['no autocomplete'] = true; |
530 | | - } elseif ( $component == 'remote autocompletion' ) { |
531 | | - $field_args['remote autocompletion'] = true; |
532 | | - } elseif ( $component == 'edittools' ) { // free text only |
533 | | - $free_text_components[] = 'edittools'; |
534 | | - } else { |
535 | | - $sub_components = explode( '=', $component, 2 ); |
536 | | - if ( count( $sub_components ) == 1 ) { |
537 | | - // add handling for single-value params, for custom input types |
538 | | - $field_args[$sub_components[0]] = null; |
539 | | - } elseif ( count( $sub_components ) == 2 ) { |
540 | | - if ( $sub_components[0] == 'input type' ) { |
541 | | - $input_type = $sub_components[1]; |
542 | | - } elseif ( $sub_components[0] == 'default' ) { |
543 | | - $default_value = $sub_components[1]; |
544 | | - } elseif ( $sub_components[0] == 'preload' ) { |
545 | | - // free text field has special handling |
546 | | - if ( $field_name == 'free text' || $field_name = '<freetext>' ) { |
547 | | - $free_text_preload_page = $sub_components[1]; |
548 | | - } else { |
549 | | - // this variable is not used |
550 | | - $preload_page = $sub_components[1]; |
551 | | - } |
552 | | - } elseif ( $sub_components[0] == 'show on select' ) { |
553 | | - // html_entity_decode() is needed to turn '>' to '>' |
554 | | - $vals = explode( ';', html_entity_decode( $sub_components[1] ) ); |
555 | | - foreach ( $vals as $val ) { |
556 | | - $option_div_pair = explode( '=>', $val, 2 ); |
557 | | - if ( count( $option_div_pair ) > 1 ) { |
558 | | - $option = $option_div_pair[0]; |
559 | | - $div_id = $option_div_pair[1]; |
560 | | - if ( array_key_exists( $div_id, $show_on_select ) ) |
561 | | - $show_on_select[$div_id][] = $option; |
562 | | - else |
563 | | - $show_on_select[$div_id] = array( $option ); |
564 | | - } else { |
565 | | - $show_on_select[$val] = array(); |
566 | | - } |
567 | | - } |
568 | | - } elseif ( $sub_components[0] == 'autocomplete on property' ) { |
569 | | - // HACK - we need to figure out if this property is a |
570 | | - // relation or attribute, i.e. whether it points to wiki |
571 | | - // pages or not; so construct an SFTemplateField object |
572 | | - // with this property, and determine it that way |
573 | | - $property_name = $sub_components[1]; |
574 | | - $dummy_field = new SFTemplateField(); |
575 | | - $dummy_field->setSemanticProperty( $property_name ); |
576 | | - if ( $dummy_field->propertyIsOfType( '_wpg' ) ) |
577 | | - $field_args['autocomplete field type'] = 'relation'; |
578 | | - else |
579 | | - $field_args['autocomplete field type'] = 'attribute'; |
580 | | - $field_args['autocompletion source'] = $sub_components[1]; |
581 | | - } elseif ( $sub_components[0] == 'autocomplete on' ) { // for backwards-compatibility |
582 | | - $field_args['autocomplete field type'] = 'category'; |
583 | | - $field_args['autocompletion source'] = $sub_components[1]; |
584 | | - } elseif ( $sub_components[0] == 'autocomplete on category' ) { |
585 | | - $field_args['autocomplete field type'] = 'category'; |
586 | | - $field_args['autocompletion source'] = $sub_components[1]; |
587 | | - } elseif ( $sub_components[0] == 'autocomplete on concept' ) { |
588 | | - $field_args['autocomplete field type'] = 'concept'; |
589 | | - $field_args['autocompletion source'] = $sub_components[1]; |
590 | | - } elseif ( $sub_components[0] == 'autocomplete on namespace' ) { |
591 | | - $field_args['autocomplete field type'] = 'namespace'; |
592 | | - $autocompletion_source = $sub_components[1]; |
593 | | - // special handling for "main" (blank) namespace |
594 | | - if ( $autocompletion_source == "" ) |
595 | | - $autocompletion_source = "main"; |
596 | | - $field_args['autocompletion source'] = $autocompletion_source; |
597 | | - } elseif ( $sub_components[0] == 'autocomplete from url' ) { |
598 | | - $field_args['autocomplete field type'] = 'external_url'; |
599 | | - $field_args['autocompletion source'] = $sub_components[1]; |
600 | | - // 'external' autocompletion is always done remotely, i.e. via API |
601 | | - $field_args['remote autocompletion'] = true; |
602 | | - } elseif ( $sub_components[0] == 'values' ) { |
603 | | - // remove whitespaces, and un-escape characters |
604 | | - $possible_values = array_map( 'trim', explode( ',', $sub_components[1] ) ); |
605 | | - $possible_values = array_map( 'htmlspecialchars_decode', $possible_values ); |
606 | | - } elseif ( $sub_components[0] == 'values from category' ) { |
607 | | - $category_name = ucfirst( $sub_components[1] ); |
608 | | - $possible_values = SFUtils::getAllPagesForCategory( $category_name, 10 ); |
609 | | - } elseif ( $sub_components[0] == 'values from concept' ) { |
610 | | - $possible_values = SFUtils::getAllPagesForConcept( $sub_components[1] ); |
611 | | - } elseif ( $sub_components[0] == 'property' ) { |
612 | | - $semantic_property = $sub_components[1]; |
613 | | - } elseif ( $sub_components[0] == 'default filename' ) { |
614 | | - $default_filename = str_replace( '<page name>', $page_name, $sub_components[1] ); |
615 | | - $field_args['default filename'] = $default_filename; |
616 | | - } else { |
617 | | - $field_args[$sub_components[0]] = $sub_components[1]; |
618 | | - } |
619 | | - // for backwards compatibility |
620 | | - if ( $sub_components[0] == 'autocomplete on' && $sub_components[1] == null ) { |
621 | | - $field_args['no autocomplete'] = true; |
622 | | - } |
623 | | - } |
624 | | - } |
625 | | - } // end for |
626 | | - if ( $allow_multiple ) |
627 | | - $field_args['part_of_multiple'] = $allow_multiple; |
628 | | - if ( count( $show_on_select ) > 0 ) |
629 | | - $field_args['show on select'] = $show_on_select; |
630 | | - // get the value from the request, if it's there, and if it's not |
631 | | - // an array |
632 | | - $escaped_field_name = str_replace( "'", "\'", $field_name ); |
633 | | - if ( isset( $template_instance_query_values ) && |
634 | | - $template_instance_query_values != null && |
635 | | - is_array( $template_instance_query_values ) && |
636 | | - array_key_exists( $escaped_field_name, $template_instance_query_values ) ) { |
637 | | - $field_query_val = $template_instance_query_values[$escaped_field_name]; |
638 | | - if ( $form_submitted || ( $field_query_val != '' && ! is_array( $field_query_val ) ) ) { |
639 | | - $cur_value = $field_query_val; |
640 | | - } |
641 | | - } else |
642 | | - $cur_value = ''; |
643 | | - // if ($cur_value && ! is_array($cur_value)) { |
644 | | - // $cur_value = htmlspecialchars($cur_value); |
645 | | - // } |
646 | | - |
647 | | - if ( $cur_value == null ) { |
648 | | - // set to default value specified in the form, if it's there |
649 | | - $cur_value = $default_value; |
650 | | - } |
651 | | - |
652 | | - // if the user is editing a page, and that page contains a call to |
653 | | - // the template being processed, get the current field's value |
654 | | - // from the template call |
655 | | - if ( $source_is_page && ( ! empty( $existing_template_text ) ) ) { |
656 | | - if ( isset( $template_contents[$field_name] ) ) { |
657 | | - $cur_value = $template_contents[$field_name]; |
658 | | - // now remove this value from $template_contents, so that |
659 | | - // at the end we can have a list of all the fields that |
660 | | - // weren't handled by the form |
661 | | - unset( $template_contents[$field_name] ); |
662 | | - } else { |
663 | | - $cur_value = ''; |
664 | | - } |
665 | | - } |
666 | | - |
667 | | - // handle the free text field - if it was declared as |
668 | | - // "field|free text" (a deprecated usage), it has to be outside |
669 | | - // of a template |
670 | | - if ( ( $template_name == '' && $field_name == 'free text' ) || |
671 | | - $field_name == '<freetext>' ) { |
672 | | - // add placeholders for the free text in both the form and |
673 | | - // the page, using <free_text> tags - once all the free text |
674 | | - // is known (at the end), it will get substituted in |
675 | | - if ( $is_hidden ) { |
676 | | - $new_text = SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' ); |
677 | | - } else { |
678 | | - if ( ! array_key_exists( 'rows', $field_args ) ) |
679 | | - $field_args['rows'] = 5; |
680 | | - if ( ! array_key_exists( 'cols', $field_args ) ) |
681 | | - $field_args['cols'] = 80; |
682 | | - $sfgTabIndex++; |
683 | | - $sfgFieldNum++; |
684 | | - list( $new_text, $new_javascript_text ) = SFFormInputs::textAreaHTML( '!free_text!', 'free_text', false, ( $form_is_disabled || $is_restricted ), $field_args ); |
685 | | - if ( in_array( 'edittools', $free_text_components ) ) { |
686 | | - // borrowed from EditPage::showEditTools() |
687 | | - $options[] = 'parse'; |
688 | | - $edittools_text = wfMsgExt( 'edittools', array( 'parse' ), array( 'content' ) ); |
689 | | - |
690 | | - $new_text .= <<<END |
691 | | - <div class="mw-editTools"> |
692 | | - $edittools_text |
693 | | - </div> |
694 | | - |
695 | | -END; |
696 | | - } |
697 | | - $fields_javascript_text .= $new_javascript_text; |
698 | | - } |
699 | | - $free_text_was_included = true; |
700 | | - // add a similar placeholder to the data text |
701 | | - $data_text .= "!free_text!\n"; |
702 | | - } |
703 | | - |
704 | | - if ( $template_name == '' || $field_name == '<freetext>' ) { |
705 | | - $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
706 | | - } else { |
707 | | - if ( is_array( $cur_value ) ) { |
708 | | - // first, check if it's a list |
709 | | - if ( array_key_exists( 'is_list', $cur_value ) && |
710 | | - $cur_value['is_list'] == true ) { |
711 | | - $cur_value_in_template = ""; |
712 | | - if ( array_key_exists( 'delimiter', $field_args ) ) { |
713 | | - $delimiter = $field_args['delimiter']; |
714 | | - } else { |
715 | | - $delimiter = ","; |
716 | | - } |
717 | | - foreach ( $cur_value as $key => $val ) { |
718 | | - if ( $key !== "is_list" ) { |
719 | | - if ( $cur_value_in_template != "" ) { |
720 | | - $cur_value_in_template .= $delimiter . " "; |
721 | | - } |
722 | | - $cur_value_in_template .= $val; |
723 | | - } |
724 | | - } |
725 | | - } else { |
726 | | - // otherwise: |
727 | | - // if it has 1 or 2 elements, assume it's a checkbox; if it has |
728 | | - // 3 elements, assume it's a date |
729 | | - // - this handling will have to get more complex if other |
730 | | - // possibilities get added |
731 | | - if ( count( $cur_value ) == 1 ) { |
732 | | - // manually load SMW's message values here, in case they |
733 | | - // didn't get loaded before |
734 | | - wfLoadExtensionMessages( 'SemanticMediaWiki' ); |
735 | | - $words_for_false = explode( ',', wfMsgForContent( 'smw_false_words' ) ); |
736 | | - // for each language, there's a series of words that are |
737 | | - // equal to false - get the word in the series that matches |
738 | | - // "no"; generally, that's the third word |
739 | | - $index_of_no = 2; |
740 | | - if ( count( $words_for_false ) > $index_of_no ) { |
741 | | - $no = ucwords( $words_for_false[$index_of_no] ); |
742 | | - } elseif ( count( $words_for_false ) == 0 ) { |
743 | | - $no = "0"; // some safe value if no words are found |
744 | | - } else { |
745 | | - $no = ucwords( $words_for_false[0] ); |
746 | | - } |
747 | | - $cur_value_in_template = $no; |
748 | | - } elseif ( count( $cur_value ) == 2 ) { |
749 | | - wfLoadExtensionMessages( 'SemanticMediaWiki' ); |
750 | | - $words_for_true = explode( ',', wfMsgForContent( 'smw_true_words' ) ); |
751 | | - // get the value in the 'true' series that tends to be "yes", |
752 | | - // and go with that one - generally, that's the third word |
753 | | - $index_of_yes = 2; |
754 | | - if ( count( $words_for_true ) > $index_of_yes ) { |
755 | | - $yes = ucwords( $words_for_true[$index_of_yes] ); |
756 | | - } elseif ( count( $words_for_true ) == 0 ) { |
757 | | - $yes = "1"; // some safe value if no words are found |
758 | | - } else { |
759 | | - $yes = ucwords( $words_for_true[0] ); |
760 | | - } |
761 | | - $cur_value_in_template = $yes; |
762 | | - // if it's 3 or greater, assume it's a date or datetime |
763 | | - } elseif ( count( $cur_value ) >= 3 ) { |
764 | | - $month = $cur_value['month']; |
765 | | - $day = $cur_value['day']; |
766 | | - if ( $day != '' ) { |
767 | | - global $wgAmericanDates; |
768 | | - if ( $wgAmericanDates == false ) { |
769 | | - // pad out day to always be two digits |
770 | | - $day = str_pad( $day, 2, "0", STR_PAD_LEFT ); |
771 | | - } |
772 | | - } |
773 | | - $year = $cur_value['year']; |
774 | | - $hour = $minute = $second = $ampm24h = $timezone = null; |
775 | | - if ( isset( $cur_value['hour'] ) ) $hour = $cur_value['hour']; |
776 | | - if ( isset( $cur_value['minute'] ) ) $minute = $cur_value['minute']; |
777 | | - if ( isset( $cur_value['second'] ) ) $second = $cur_value['second']; |
778 | | - if ( isset( $cur_value['ampm24h'] ) ) $ampm24h = $cur_value['ampm24h']; |
779 | | - if ( isset( $cur_value['timezone'] ) ) $timezone = $cur_value['timezone']; |
780 | | - if ( $month != '' && $day != '' && $year != '' ) { |
781 | | - // special handling for American dates - otherwise, just |
782 | | - // the standard year/month/day (where month is a number) |
783 | | - global $wgAmericanDates; |
784 | | - if ( $wgAmericanDates == true ) { |
785 | | - $cur_value_in_template = "$month $day, $year"; |
786 | | - } else { |
787 | | - $cur_value_in_template = "$year/$month/$day"; |
788 | | - } |
789 | | - // include whatever time information we have |
790 | | - if ( ! is_null( $hour ) ) |
791 | | - $cur_value_in_template .= " " . str_pad( intval( substr( $hour, 0, 2 ) ), 2, '0', STR_PAD_LEFT ) . ":" . str_pad( intval( substr( $minute, 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
792 | | - if ( ! is_null( $second ) ) |
793 | | - $cur_value_in_template .= ":" . str_pad( intval( substr( $second, 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
794 | | - if ( ! is_null( $ampm24h ) ) |
795 | | - $cur_value_in_template .= " $ampm24h"; |
796 | | - if ( ! is_null( $timezone ) ) |
797 | | - $cur_value_in_template .= " $timezone"; |
798 | | - } else { |
799 | | - $cur_value_in_template = ""; |
800 | | - } |
801 | | - } |
802 | | - } |
803 | | - } else { // value is not an array |
804 | | - $cur_value_in_template = $cur_value; |
805 | | - } |
806 | | - if ( $query_template_name == null || $query_template_name == '' ) |
807 | | - $input_name = $field_name; |
808 | | - elseif ( $allow_multiple ) |
809 | | - // 'num' will get replaced by an actual index, either in PHP |
810 | | - // or in Javascript, later on |
811 | | - $input_name = $query_template_name . '[num][' . $field_name . ']'; |
812 | | - else |
813 | | - $input_name = $query_template_name . '[' . $field_name . ']'; |
814 | | - |
815 | | - // if we're creating the page name from a formula based on |
816 | | - // form values, see if the current input is part of that formula, |
817 | | - // and if so, substitute in the actual value |
818 | | - if ( $form_submitted && $generated_page_name != '' ) { |
819 | | - // this line appears unnecessary |
820 | | - // $generated_page_name = str_replace('.', '_', $generated_page_name); |
821 | | - $generated_page_name = str_replace( ' ', '_', $generated_page_name ); |
822 | | - $escaped_input_name = str_replace( ' ', '_', $input_name ); |
823 | | - $generated_page_name = str_ireplace( "<$escaped_input_name>", $cur_value_in_template, $generated_page_name ); |
824 | | - // once the substitution is done, replace underlines back |
825 | | - // with spaces |
826 | | - $generated_page_name = str_replace( '_', ' ', $generated_page_name ); |
827 | | - } |
828 | | - // disable this field if either the whole form is disabled, or |
829 | | - // it's a restricted field and user doesn't have sysop privileges |
830 | | - $is_disabled = ( $form_is_disabled || |
831 | | - ( $is_restricted && ( ! $wgUser || ! $wgUser->isAllowed( 'editrestrictedfields' ) ) ) ); |
832 | | - // create an SFFormField instance based on all the |
833 | | - // parameters in the form definition, and any information from |
834 | | - // the template definition (contained in the $all_fields parameter) |
835 | | - $form_field = SFFormField::createFromDefinition( $field_name, $input_name, |
836 | | - $is_mandatory, $is_hidden, $is_uploadable, $possible_values, $is_disabled, |
837 | | - $is_list, $input_type, $field_args, $all_fields, $strict_parsing ); |
838 | | - // if a property was set in the form definition, overwrite whatever |
839 | | - // is set in the template field - this is somewhat of a hack, since |
840 | | - // parameters set in the form definition are meant to go into the |
841 | | - // SFFormField object, not the SFTemplateField object it contains; |
842 | | - // it seemed like too much work, though, to create an |
843 | | - // SFFormField::setSemanticProperty() function just for this call |
844 | | - if ( $semantic_property != null ) |
845 | | - $form_field->template_field->setSemanticProperty( $semantic_property ); |
846 | | - |
847 | | - // call hooks - unfortunately this has to be split into two |
848 | | - // separate calls, because of the different variable names in |
849 | | - // each case |
850 | | - if ( $form_submitted ) |
851 | | - wfRunHooks( 'sfCreateFormField', array( &$form_field, &$cur_value_in_template, true ) ); |
852 | | - else |
853 | | - wfRunHooks( 'sfCreateFormField', array( &$form_field, &$cur_value, false ) ); |
854 | | - // if this is not part of a 'multiple' template, increment the |
855 | | - // global tab index (used for correct tabbing) |
856 | | - if ( ! array_key_exists( 'part_of_multiple', $field_args ) ) |
857 | | - $sfgTabIndex++; |
858 | | - // increment the global field number regardless |
859 | | - $sfgFieldNum++; |
860 | | - // if the field is a date field, and its default value was set |
861 | | - // to 'now', and it has no current value, set $cur_value to be |
862 | | - // the current date |
863 | | - if ( $default_value == 'now' && |
864 | | - // if the date is hidden, cur_value will already be set |
865 | | - // to the default value |
866 | | - ( $cur_value == '' || $cur_value == 'now' ) ) { |
867 | | - if ( $input_type == 'date' || $input_type == 'datetime' || |
868 | | - $input_type == 'datetime with timezone' || $input_type == 'year' || |
869 | | - ( $input_type == '' && $form_field->template_field->propertyIsOfType( '_dat' ) ) ) { |
870 | | - // get current time, for the time zone specified in the wiki |
871 | | - global $wgLocaltimezone; |
872 | | - putenv( 'TZ=' . $wgLocaltimezone ); |
873 | | - $cur_time = time(); |
874 | | - $year = date( "Y", $cur_time ); |
875 | | - $month = date( "n", $cur_time ); |
876 | | - $day = date( "j", $cur_time ); |
877 | | - global $wgAmericanDates, $sfg24HourTime; |
878 | | - if ( $wgAmericanDates == true ) { |
879 | | - $month_names = SFFormUtils::getMonthNames(); |
880 | | - $month_name = $month_names[$month - 1]; |
881 | | - $cur_value_in_template = "$month_name $day, $year"; |
882 | | - } else { |
883 | | - $cur_value_in_template = "$year/$month/$day"; |
884 | | - } |
885 | | - if ( $input_type == 'datetime' || $input_type == 'datetime with timezone' ) { |
886 | | - if ( $sfg24HourTime ) { |
887 | | - $hour = str_pad( intval( substr( date( "G", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
888 | | - } else { |
889 | | - $hour = str_pad( intval( substr( date( "g", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
890 | | - } |
891 | | - $minute = str_pad( intval( substr( date( "i", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
892 | | - $second = str_pad( intval( substr( date( "s", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
893 | | - if ( $sfg24HourTime ) { |
894 | | - $cur_value_in_template .= " $hour:$minute:$second"; |
895 | | - } else { |
896 | | - $ampm = date( "A", $cur_time ); |
897 | | - $cur_value_in_template .= " $hour:$minute:$second $ampm"; |
898 | | - } |
899 | | - } |
900 | | - if ( $input_type == 'datetime with timezone' ) { |
901 | | - $timezone = date( "T", $cur_time ); |
902 | | - $cur_value_in_template .= " $timezone"; |
903 | | - } |
904 | | - } |
905 | | - } |
906 | | - // if the field is a text field, and its default value was set |
907 | | - // to 'current user', and it has no current value, set $cur_value |
908 | | - // to be the current user |
909 | | - if ( $default_value == 'current user' && |
910 | | - // if the date is hidden, cur_value will already be set |
911 | | - // to the default value |
912 | | - ( $cur_value == '' || $cur_value == 'current user' ) ) { |
913 | | - if ( $input_type == 'text' || $input_type == '' ) { |
914 | | - $cur_value_in_template = $wgUser->getName(); |
915 | | - $cur_value = $cur_value_in_template; |
916 | | - } |
917 | | - } |
918 | | - list( $new_text, $new_javascript_text ) = $this->formFieldHTML( $form_field, $cur_value ); |
919 | | - |
920 | | - $fields_javascript_text .= $new_javascript_text; |
921 | | - |
922 | | - // if this field is disabled, add a hidden field holding |
923 | | - // the value of this field, because disabled inputs for some |
924 | | - // reason don't submit their value |
925 | | - if ( $form_field->is_disabled ) { |
926 | | - if ( $field_name == 'free text' || $field_name == '<freetext>' ) { |
927 | | - $new_text .= SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' ); |
928 | | - } else { |
929 | | - $new_text .= SFFormUtils::hiddenFieldHTML( $input_name, $cur_value ); |
930 | | - } |
931 | | - } |
932 | | - |
933 | | - if ( $new_text ) { |
934 | | - // include the field name only for non-numeric field names |
935 | | - if ( is_numeric( $field_name ) ) { |
936 | | - $template_text .= "|$cur_value_in_template"; |
937 | | - } else { |
938 | | - // if the value is null, don't include it at all |
939 | | - if ( $cur_value_in_template != '' ) |
940 | | - $template_text .= "\n|$field_name=$cur_value_in_template"; |
941 | | - } |
942 | | - $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
943 | | - // also add to Javascript validation code |
944 | | - $input_id = "input_" . $sfgFieldNum; |
945 | | - $info_id = "info_" . $sfgFieldNum; |
946 | | - if ( $is_mandatory ) { |
947 | | - if ( $input_type == 'date' || $input_type == 'datetime' || $input_type == 'datetime with timezone' || |
948 | | - ( $input_type == '' && $form_field->template_field->propertyIsOfType( '_dat' ) ) ) { |
949 | | - $sfgJSValidationCalls[] = "validate_mandatory_field ('$input_id" . "_month', '$info_id')"; |
950 | | - $sfgJSValidationCalls[] = "validate_mandatory_field ('$input_id" . "_day', '$info_id')"; |
951 | | - $sfgJSValidationCalls[] = "validate_mandatory_field ('$input_id" . "_year', '$info_id')"; |
952 | | - if ( $input_type == 'datetime' || $input_type == 'datetime with timezone' ) { |
953 | | - // TODO - validate the time fields |
954 | | - if ( $input_type == 'datetime with timezone' ) { |
955 | | - // TODO - validate the timezone |
956 | | - } |
957 | | - } |
958 | | - } else { |
959 | | - if ( $allow_multiple ) { |
960 | | - if ( $all_instances_printed ) { |
961 | | - $sfgJSValidationCalls[] = "validate_multiple_mandatory_fields($sfgFieldNum)"; |
962 | | - } else { |
963 | | - $sfgJSValidationCalls[] = "validate_mandatory_field(\"input_$sfgFieldNum\", \"info_$sfgFieldNum\")"; |
964 | | - } |
965 | | - } elseif ( $input_type == 'radiobutton' || $input_type == 'category' ) { |
966 | | - // only add this if there's a "None" option |
967 | | - if ( empty( $default_value ) ) { |
968 | | - $sfgJSValidationCalls[] = "validate_mandatory_radiobutton('$input_id', '$info_id')"; |
969 | | - } |
970 | | - } elseif ( ( $form_field->template_field->is_list && $form_field->template_field->field_type == 'enumeration' && $input_type != 'listbox' ) || ( $input_type == 'checkboxes' ) ) { |
971 | | - $sfgJSValidationCalls[] = "validate_mandatory_checkboxes('$input_id', '$info_id')"; |
972 | | - } else { |
973 | | - $sfgJSValidationCalls[] = "validate_mandatory_field('$input_id', '$info_id')"; |
974 | | - } |
975 | | - } |
976 | | - } |
977 | | - } else { |
978 | | - $start_position = $brackets_end_loc; |
979 | | - } |
980 | | - } |
981 | | - // ===================================================== |
982 | | - // standard input processing |
983 | | - // ===================================================== |
984 | | - } elseif ( $tag_title == 'standard input' ) { |
985 | | - // handle all the possible values |
986 | | - $input_name = $tag_components[1]; |
987 | | - $input_label = null; |
988 | | - $attr = array(); |
989 | | - |
990 | | - // if it's a query, ignore all standard inputs except run query |
991 | | - if ( ( $is_query && $input_name != 'run query' ) || ( !$is_query && $input_name == 'run query' ) ) { |
992 | | - $new_text = ""; |
993 | | - $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
994 | | - continue; |
995 | | - } |
996 | | - // set a flag so that the standard 'form bottom' won't get displayed |
997 | | - $this->standardInputsIncluded = true; |
998 | | - // cycle through the other components |
999 | | - for ( $i = 2; $i < count( $tag_components ); $i++ ) { |
1000 | | - $component = $tag_components[$i]; |
1001 | | - $sub_components = explode( '=', $component ); |
1002 | | - if ( count( $sub_components ) == 1 ) { |
1003 | | - if ( $sub_components[0] == 'edittools' ) { |
1004 | | - $free_text_components[] = 'edittools'; |
1005 | | - } |
1006 | | - } elseif ( count( $sub_components ) == 2 ) { |
1007 | | - switch( $sub_components[0] ) { |
1008 | | - case 'label': |
1009 | | - $input_label = $sub_components[1]; |
1010 | | - break; |
1011 | | - case 'class': |
1012 | | - case 'style': |
1013 | | - $attr[$sub_components[0]] = $sub_components[1]; |
1014 | | - break; |
1015 | | - } |
1016 | | - // free text input needs more handling than the rest |
1017 | | - if ( $input_name == 'free text' || $input_name == '<freetext>' ) { |
1018 | | - if ( $sub_components[0] == 'preload' ) { |
1019 | | - $free_text_preload_page = $sub_components[1]; |
1020 | | - } |
1021 | | - } |
1022 | | - } |
1023 | | - } |
1024 | | - if ( $input_name == 'summary' ) { |
1025 | | - $new_text = SFFormUtils::summaryInputHTML( $form_is_disabled, $input_label, $attr ); |
1026 | | - } elseif ( $input_name == 'minor edit' ) { |
1027 | | - $new_text = SFFormUtils::minorEditInputHTML( $form_is_disabled, $input_label, $attr ); |
1028 | | - } elseif ( $input_name == 'watch' ) { |
1029 | | - $new_text = SFFormUtils::watchInputHTML( $form_is_disabled, $input_label, $attr ); |
1030 | | - } elseif ( $input_name == 'save' ) { |
1031 | | - $new_text = SFFormUtils::saveButtonHTML( $form_is_disabled, $input_label, $attr ); |
1032 | | - } elseif ( $input_name == 'preview' ) { |
1033 | | - $new_text = SFFormUtils::showPreviewButtonHTML( $form_is_disabled, $input_label, $attr ); |
1034 | | - } elseif ( $input_name == 'changes' ) { |
1035 | | - $new_text = SFFormUtils::showChangesButtonHTML( $form_is_disabled, $input_label, $attr ); |
1036 | | - } elseif ( $input_name == 'cancel' ) { |
1037 | | - $new_text = SFFormUtils::cancelLinkHTML( $form_is_disabled, $input_label, $attr ); |
1038 | | - } elseif ( $input_name == 'run query' ) { |
1039 | | - $new_text = SFFormUtils::runQueryButtonHTML( $form_is_disabled, $input_label, $attr ); |
1040 | | - } |
1041 | | - $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
1042 | | - // ===================================================== |
1043 | | - // page info processing |
1044 | | - // ===================================================== |
1045 | | - } elseif ( $tag_title == 'info' ) { |
1046 | | - // TODO: Generate an error message if this is included more than once |
1047 | | - foreach ( array_slice( $tag_components, 1 ) as $component ) { |
1048 | | - $sub_components = explode( '=', $component, 2 ); |
1049 | | - $tag = $sub_components[0]; |
1050 | | - if ( $tag == 'create title' || $tag == 'add title' ) { |
1051 | | - // handle this only if we're adding a page |
1052 | | - if ( ! $this->mPageTitle->exists() ) { |
1053 | | - $val = $sub_components[1]; |
1054 | | - $form_page_title = $val; |
1055 | | - } |
1056 | | - } |
1057 | | - elseif ( $tag == 'edit title' ) { |
1058 | | - // handle this only if we're editing a page |
1059 | | - if ( $this->mPageTitle->exists() ) { |
1060 | | - $val = $sub_components[1]; |
1061 | | - $form_page_title = $val; |
1062 | | - } |
1063 | | - } |
1064 | | - elseif ( $tag == 'partial form' ) { |
1065 | | - $form_is_partial = true; |
1066 | | - // replacement pages may have minimal matches... |
1067 | | - $source_page_matches_this_form = true; |
1068 | | - } |
1069 | | - elseif ( $tag == 'includeonly free text' || $tag == 'onlyinclude free text' ) { |
1070 | | - $onlyinclude_free_text = true; |
1071 | | - } |
1072 | | - } |
1073 | | - $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
1074 | | - // ===================================================== |
1075 | | - // default outer level processing |
1076 | | - // ===================================================== |
1077 | | - } else { // tag is not one of the three allowed values |
1078 | | - // ignore tag |
1079 | | - $start_position = $brackets_end_loc; |
1080 | | - } // end if |
1081 | | - } // end while |
1082 | | - |
1083 | | - if ( ! $all_instances_printed ) { |
1084 | | - if ( $template_text != '' ) { |
1085 | | - // for mostly aesthetic purposes, if the template call ends with |
1086 | | - // a bunch of pipes (i.e., it's an indexed template with unused |
1087 | | - // parameters at the end), remove the pipes |
1088 | | - $template_text = preg_replace( '/\|*$/', '', $template_text ); |
1089 | | - // add another newline before the final bracket, if this template |
1090 | | - // call is already more than one line |
1091 | | - if ( strpos( $template_text, "\n" ) ) |
1092 | | - $template_text .= "\n"; |
1093 | | - // if we're editing an existing page, and there were fields in |
1094 | | - // the template call not handled by this form, preserve those |
1095 | | - $template_text .= SFFormUtils::addUnhandledFields(); |
1096 | | - $template_text .= "}}"; |
1097 | | - $data_text .= $template_text . "\n"; |
1098 | | - // if there is a placeholder in the text, we know that we are |
1099 | | - // doing a replace |
1100 | | - if ( $existing_page_content && strpos( $existing_page_content, '{{{insertionpoint}}}', 0 ) !== false ) { |
1101 | | - $existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}(\r?\n?)/', |
1102 | | - preg_replace( '/\}\}/m', '}�', |
1103 | | - preg_replace( '/\{\{/m', '�{', $template_text ) ) . |
1104 | | - "\n{{{insertionpoint}}}", |
1105 | | - $existing_page_content ); |
1106 | | - // otherwise, if it's a partial form, we have to add the new |
1107 | | - // text somewhere |
1108 | | - } elseif ( $form_is_partial && $wgRequest->getCheck( 'partial' ) ) { |
1109 | | - $existing_page_content = preg_replace( '/\}\}/m', '}�', |
1110 | | - preg_replace( '/\{\{/m', '�{', $template_text ) ) . |
1111 | | - "\n{{{insertionpoint}}}\n" . $existing_page_content; |
1112 | | - } |
1113 | | - } |
1114 | | - } |
1115 | | - |
1116 | | - if ( $allow_multiple ) { |
1117 | | - if ( ! $all_instances_printed ) { |
1118 | | - // add the character "a" onto the instance number of this input |
1119 | | - // in the form, to differentiate the inputs the form starts out |
1120 | | - // with from any inputs added by the Javascript |
1121 | | - $section = str_replace( '[num]', "[{$instance_num}a]", $section ); |
1122 | | - $remove_text = wfMsg( 'sf_formedit_remove' ); |
1123 | | - $form_text .= <<<END |
1124 | | - <div id="wrapper_$sfgFieldNum" class="multipleTemplate"> |
1125 | | - $section |
1126 | | - <input type="button" onclick="removeInstance('wrapper_$sfgFieldNum');" value="$remove_text" tabindex="$sfgTabIndex" class="remove" /> |
1127 | | - </div> |
1128 | | - |
1129 | | -END; |
1130 | | - // this will cause the section to be re-parsed on the next go |
1131 | | - $section_num--; |
1132 | | - // because there is an instance, the fieldset will never be hidden, |
1133 | | - // even if choosers are being used. So, do not hide the fieldset. |
1134 | | - $form_text = str_replace( "[[placeholder]]", "", $form_text ); |
1135 | | - } else { |
1136 | | - // this is the last instance of this template - stick an 'add' |
1137 | | - // button in the form |
1138 | | - $form_text .= <<<END |
1139 | | - <div id="starter_$query_template_name" class="multipleTemplate" style="display: none;"> |
1140 | | - $section |
1141 | | - </div> |
1142 | | - <div id="main_$query_template_name"></div> |
1143 | | - |
1144 | | -END; |
1145 | | - $add_another = wfMsg( 'sf_formedit_addanother' ); |
1146 | | - $form_text .= <<<END |
1147 | | - <p style="margin-left:10px;"> |
1148 | | - <p><input type="button" onclick="addInstance('starter_$query_template_name', 'main_$query_template_name', '$sfgFieldNum');" value="$add_another" tabindex="$sfgTabIndex" class="addAnother" /></p> |
1149 | | - |
1150 | | -END; |
1151 | | - // if a chooser is being used for this template, add the template |
1152 | | - // to the chooser data array |
1153 | | - if ( $chooser_name !== false ) |
1154 | | - $choosers[$chooser_name][] = array( $query_template_name, $sfgFieldNum, $chooser_caption ); |
1155 | | - } |
1156 | | - } else { |
1157 | | - $form_text .= $section; |
1158 | | - } |
1159 | | - |
1160 | | - } // end for |
1161 | | - |
1162 | | - // if it wasn't included in the form definition, add the |
1163 | | - // 'free text' input as a hidden field at the bottom |
1164 | | - if ( ! $free_text_was_included ) { |
1165 | | - $form_text .= SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' ); |
1166 | | - } |
1167 | | - // get free text, and add to page data, as well as retroactively |
1168 | | - // inserting it into the form |
1169 | | - |
1170 | | - // If $form_is_partial is true then either: |
1171 | | - // (a) we're processing a replacement (param 'partial' == 1) |
1172 | | - // (b) we're sending out something to be replaced (param 'partial' is missing) |
1173 | | - if ( $form_is_partial ) { |
1174 | | - if ( !$wgRequest->getCheck( 'partial' ) ) { |
1175 | | - $free_text = $original_page_content; |
1176 | | - $form_text .= SFFormUtils::hiddenFieldHTML( 'partial', 1 ); |
1177 | | - } else { |
1178 | | - $free_text = null; |
1179 | | - $existing_page_content = preg_replace( '/�\{(.*?)\}�/s', '{{\1}}', $existing_page_content ); |
1180 | | - $existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}/', '', $existing_page_content ); |
1181 | | - } |
1182 | | - } elseif ( $source_is_page ) { |
1183 | | - // if the page is the source, free_text will just be whatever in the |
1184 | | - // page hasn't already been inserted into the form |
1185 | | - $free_text = trim( $existing_page_content ); |
1186 | | - // or get it from a form submission |
1187 | | - } elseif ( $wgRequest->getCheck( 'free_text' ) ) { |
1188 | | - $free_text = $wgRequest->getVal( 'free_text' ); |
1189 | | - if ( ! $free_text_was_included ) { |
1190 | | - $data_text .= "!free_text!"; |
1191 | | - } |
1192 | | - // or get it from the form definition |
1193 | | - } elseif ( $free_text_preload_page != null ) { |
1194 | | - $free_text = SFFormUtils::getPreloadedText( $free_text_preload_page ); |
1195 | | - } else { |
1196 | | - $free_text = null; |
1197 | | - } |
1198 | | - if ( $onlyinclude_free_text ) { |
1199 | | - // modify free text and data text to insert <onlyinclude> tags |
1200 | | - $free_text = str_replace( "<onlyinclude>", '', $free_text ); |
1201 | | - $free_text = str_replace( "</onlyinclude>", '', $free_text ); |
1202 | | - $free_text = trim( $free_text ); |
1203 | | - $data_text = str_replace( '!free_text!', '<onlyinclude>!free_text!</onlyinclude>', $data_text ); |
1204 | | - } |
1205 | | - // if the FCKeditor extension is installed, use that for the free text input |
1206 | | - global $wgFCKEditorDir; |
1207 | | - if ( $wgFCKEditorDir ) { |
1208 | | - $showFCKEditor = SFFormUtils::getShowFCKEditor(); |
1209 | | - if ( !$form_submitted && ( $showFCKEditor & RTE_VISIBLE ) ) { |
1210 | | - $free_text = SFFormUtils::prepareTextForFCK( $free_text ); |
1211 | | - } |
1212 | | - } else { |
1213 | | - $showFCKEditor = 0; |
1214 | | - } |
1215 | | - // now that we have it, substitute free text into the form and page |
1216 | | - $escaped_free_text = Sanitizer::safeEncodeAttribute( $free_text ); |
1217 | | - $form_text = str_replace( '!free_text!', $escaped_free_text, $form_text ); |
1218 | | - $data_text = str_replace( '!free_text!', $free_text, $data_text ); |
1219 | | - |
1220 | | - // add a warning in, if we're editing an existing page and that page |
1221 | | - // appears to not have been created with this form |
1222 | | - if ( $this->mPageTitle->exists() && ( $existing_page_content != '' ) && ! $source_page_matches_this_form ) { |
1223 | | - $form_text = ' <div class="warningMessage">' . wfMsg( 'sf_formedit_formwarning', $this->mPageTitle->getFullURL() ) . "</div>\n" . $form_text; |
1224 | | - } |
1225 | | - |
1226 | | - // Substitute the choosers in here too. |
1227 | | - $chooser_count = 0; |
1228 | | - $chooser_text = ""; |
1229 | | - $using_choosers = "false"; |
1230 | | - foreach ( $choosers as $choosername => $chooser ) { |
1231 | | - if ( count( $chooser ) != 0 ) { |
1232 | | - $chooser_count++; |
1233 | | - if ( $chooser_count == 1 ) { |
1234 | | - // emit the initial javascript code |
1235 | | - $using_choosers = "true"; |
1236 | | - $chooser_text .= <<<END |
1237 | | -<script type="text/javascript">/* <![CDATA[ */ |
1238 | | - |
1239 | | -function updatechooserbutton(f,n) |
1240 | | -{ |
1241 | | - document.getElementById(n).disabled = (f.options[f.selectedIndex].value=="invalid"); |
1242 | | -} |
1243 | | - |
1244 | | -function addInstanceFromChooser(chooserid) |
1245 | | -{ |
1246 | | - var chooser = document.getElementById(chooserid); |
1247 | | - var optionstring = chooser.options[chooser.selectedIndex].value; |
1248 | | - var pos = optionstring.indexOf(","); |
1249 | | - var tabindex = optionstring.substr(0,pos); |
1250 | | - var chooservalue = optionstring.substr(pos+1); |
1251 | | - addInstance('starter_' + chooservalue, 'main_' + chooservalue, parseInt(tabindex)); |
1252 | | -} |
1253 | | - |
1254 | | -//The fieldset containing the given element was just updated. If the fieldset is associated with a chooser, |
1255 | | -//ensure that the fieldset is hidden if and only if there are no template instances inside. |
1256 | | -function hideOrShowFieldset(element) |
1257 | | -{ |
1258 | | - //Find fieldset |
1259 | | - while (element.tagName.toLowerCase() != "fieldset") |
1260 | | - element = element.parentNode; |
1261 | | - //Bail out if fieldset is not part of chooser |
1262 | | - if (!element.getAttribute("haschooser")) |
1263 | | - return; |
1264 | | - //Now look for "input" or "select" tags that don't look like they're part of the starter template |
1265 | | - var inputs = element.getElementsByTagName("input"); |
1266 | | - var x; |
1267 | | - var show = false; |
1268 | | - for (x=0;x<inputs.length;x++) |
1269 | | - { |
1270 | | - if (inputs[x].type=="text" && inputs[x].name.indexOf("[num]") == -1) |
1271 | | - show = true; |
1272 | | - } |
1273 | | - var selects = element.getElementsByTagName("select"); |
1274 | | - for (x=0;x<selects.length;x++) |
1275 | | - { |
1276 | | - if (selects[x].name.indexOf("[num]") == -1) |
1277 | | - show = true; |
1278 | | - } |
1279 | | - //Now show or hide fieldset |
1280 | | - element.style.display = (show?"block":"none"); |
1281 | | -} |
1282 | | -/* ]]> */ </script> |
1283 | | - |
1284 | | -END; |
1285 | | - } |
1286 | | - |
1287 | | - $chooser_text .= "<p>$choosername:<select id='chooserselect$chooser_count' size='1' onchange='updatechooserbutton(this,\"chooserbutton$chooser_count\")'>\n"; |
1288 | | - $chooser_text .= "<option value='invalid'>" . wfMsg( 'sf_createform_choosefield' ) . "</option>\n"; |
1289 | | - foreach ( $chooser as $chooser_item ) { |
1290 | | - $chooser_value = str_replace( '"', '\\"', $chooser_item[0] ); |
1291 | | - $tabindex = $chooser_item[1]; |
1292 | | - $chooser_caption = $chooser_item[2]; |
1293 | | - if ( $chooser_caption === false ) |
1294 | | - $chooser_caption = str_replace( '_', ' ', $chooser_value ); |
1295 | | - $chooser_text .= "<option value=\"$tabindex ,$chooser_value\">$chooser_caption</option>\n"; |
1296 | | - } |
1297 | | - $chooser_text .= "</select>\n"; |
1298 | | - } |
1299 | | - $chooser_text .= "<input type='button' onclick=\"addInstanceFromChooser('chooserselect$chooser_count');\" value='" . wfMsg( 'sf_formedit_addanother' ) . "' disabled='true' id='chooserbutton$chooser_count'></p>"; |
1300 | | - } |
1301 | | - |
1302 | | - $form_text = str_replace( '{{{choosers}}}', $chooser_text, $form_text ); |
1303 | | - |
1304 | | - // add form bottom, if no custom "standard inputs" have been defined |
1305 | | - if ( !$this->standardInputsIncluded ) { |
1306 | | - if ( $is_query ) |
1307 | | - $form_text .= SFFormUtils::queryFormBottom( $form_is_disabled ); |
1308 | | - else |
1309 | | - $form_text .= SFFormUtils::formBottom( $form_is_disabled ); |
1310 | | - } |
1311 | | - $starttime = wfTimestampNow(); |
1312 | | - $page_article = new Article( $this->mPageTitle ); |
1313 | | - $edittime = $page_article->getTimestamp(); |
1314 | | - if ( !$is_query ) |
1315 | | - $form_text .= <<<END |
1316 | | - |
1317 | | - <input type="hidden" value="$starttime" name="wpStarttime" /> |
1318 | | - <input type="hidden" value="$edittime" name="wpEdittime" /> |
1319 | | -END; |
1320 | | - $form_text .= <<<END |
1321 | | - </form> |
1322 | | - |
1323 | | -END; |
1324 | | - |
1325 | | - // add Javascript code for form-wide use |
1326 | | - $javascript_text .= SFFormUtils::validationJavascript(); |
1327 | | - $javascript_text .= SFFormUtils::instancesJavascript( $using_choosers ); |
1328 | | - $javascript_text .= SFFormUtils::autocompletionJavascript(); |
1329 | | - if ( $free_text_was_included && $showFCKEditor > 0 ) { |
1330 | | - $javascript_text .= SFFormUtils::mainFCKJavascript( $showFCKEditor ); |
1331 | | - if ( $showFCKEditor & ( RTE_TOGGLE_LINK | RTE_POPUP ) ) { |
1332 | | - $javascript_text .= SFFormUTils::FCKToggleJavascript(); |
1333 | | - } |
1334 | | - if ( $showFCKEditor & RTE_POPUP ) { |
1335 | | - $javascript_text .= SFFormUTils::FCKPopupJavascript(); |
1336 | | - } |
1337 | | - } |
1338 | | - |
1339 | | - // send the autocomplete values to the browser, along with the mappings |
1340 | | - // of which values should apply to which fields |
1341 | | - // if doing a replace, the data text is actually the modified original page |
1342 | | - if ( $wgRequest->getCheck( 'partial' ) ) |
1343 | | - $data_text = $existing_page_content; |
1344 | | - $javascript_text .= $fields_javascript_text; |
1345 | | - global $wgParser; |
1346 | | - $new_text = ""; |
1347 | | - if ( !$embedded ) |
1348 | | - $new_text = $wgParser->preprocess( str_replace( "{{!}}", "|", $form_page_title ), $this->mPageTitle, new ParserOptions() ); |
1349 | | - |
1350 | | - return array( $form_text, "/*<![CDATA[*/ $javascript_text /*]]>*/", |
1351 | | - $data_text, $new_text, $generated_page_name ); |
1352 | | - } |
1353 | | - |
1354 | | - /** |
1355 | | - * Create the HTML and Javascript to display this field within a form |
1356 | | - */ |
1357 | | - function formFieldHTML( $form_field, $cur_value ) { |
1358 | | - global $smwgContLang; |
1359 | | - |
1360 | | - // also get the actual field, with all the semantic information (type is |
1361 | | - // SFTemplateField, instead of SFFormField) |
1362 | | - $template_field = $form_field->template_field; |
1363 | | - |
1364 | | - if ( $form_field->is_hidden ) { |
1365 | | - $text = SFFormUtils::hiddenFieldHTML( $form_field->input_name, $cur_value ); |
1366 | | - $javascript_text = ""; |
1367 | | - } elseif ( $form_field->input_type != '' && |
1368 | | - array_key_exists( $form_field->input_type, $this->mInputTypeHooks ) && |
1369 | | - $this->mInputTypeHooks[$form_field->input_type] != null ) { |
1370 | | - $funcArgs = array(); |
1371 | | - $funcArgs[] = $cur_value; |
1372 | | - $funcArgs[] = $form_field->input_name; |
1373 | | - $funcArgs[] = $form_field->is_mandatory; |
1374 | | - $funcArgs[] = $form_field->is_disabled; |
1375 | | - // last argument to function should be a hash, merging the default |
1376 | | - // values for this input type with all other properties set in |
1377 | | - // the form definition, plus some semantic-related arguments |
1378 | | - $hook_values = $this->mInputTypeHooks[$form_field->input_type]; |
1379 | | - $other_args = $form_field->getArgumentsForInputCall( $hook_values[1] ); |
1380 | | - $funcArgs[] = $other_args; |
1381 | | - list( $text, $javascript_text ) = call_user_func_array( $hook_values[0], $funcArgs ); |
1382 | | - } else { // input type not defined in form |
1383 | | - $field_type = $template_field->field_type; |
1384 | | - $is_list = ( $form_field->is_list || $template_field->is_list ); |
1385 | | - if ( $field_type != '' && |
1386 | | - array_key_exists( $field_type, $this->mSemanticTypeHooks ) && |
1387 | | - isset( $this->mSemanticTypeHooks[$field_type][$is_list] ) ) { |
1388 | | - $funcArgs = array(); |
1389 | | - $funcArgs[] = $cur_value; |
1390 | | - $funcArgs[] = $form_field->input_name; |
1391 | | - $funcArgs[] = $form_field->is_mandatory; |
1392 | | - $funcArgs[] = $form_field->is_disabled; |
1393 | | - $hook_values = $this->mSemanticTypeHooks[$field_type][$is_list]; |
1394 | | - $other_args = $form_field->getArgumentsForInputCall( $hook_values[1] ); |
1395 | | - $funcArgs[] = $other_args; |
1396 | | - list( $text, $javascript_text ) = call_user_func_array( $hook_values[0], $funcArgs ); |
1397 | | - } else { // anything else |
1398 | | - $other_args = $form_field->getArgumentsForInputCall(); |
1399 | | - // special call to ensure that a list input is the right default size |
1400 | | - if ( $form_field->is_list ) { |
1401 | | - if ( ! array_key_exists( 'size', $other_args ) ) |
1402 | | - $other_args['size'] = 100; |
1403 | | - } |
1404 | | - list( $text, $javascript_text ) = SFFormInputs::textEntryHTML( $cur_value, $form_field->input_name, $form_field->is_mandatory, $form_field->is_disabled, $other_args ); |
1405 | | - } |
1406 | | - } |
1407 | | - return array( $text, $javascript_text ); |
1408 | | - } |
1409 | | - |
1410 | | -} |
Index: trunk/extensions/SemanticForms/includes/SF_LinkUtils.inc |
— | — | @@ -1,305 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Helper functions for linking to pages and forms |
5 | | - * |
6 | | - * @author Yaron Koren |
7 | | - */ |
8 | | - |
9 | | -if ( !defined( 'MEDIAWIKI' ) ) die(); |
10 | | - |
11 | | -class SFLinkUtils { |
12 | | - |
13 | | - static function linkText( $namespace, $name, $text = NULL ) { |
14 | | - global $wgContLang; |
15 | | - |
16 | | - $inText = $wgContLang->getNsText( $namespace ) . ':' . $name; |
17 | | - $title = Title::newFromText( $inText ); |
18 | | - if ( $title === NULL ) { |
19 | | - return $inText; // TODO maybe report an error here? |
20 | | - } |
21 | | - if ( NULL === $text ) $text = $title->getText(); |
22 | | - $l = new Linker(); |
23 | | - return $l->makeLinkObj( $title, $text ); |
24 | | - } |
25 | | - |
26 | | - /** |
27 | | - * Creates the name of the page that appears in the URL; |
28 | | - * this method is necessary because Title::getPartialURL(), for |
29 | | - * some reason, doesn't include the namespace |
30 | | - */ |
31 | | - static function titleURLString( $title ) { |
32 | | - global $wgCapitalLinks; |
33 | | - |
34 | | - $namespace = wfUrlencode( $title->getNsText() ); |
35 | | - if ( '' != $namespace ) { |
36 | | - $namespace .= ':'; |
37 | | - } |
38 | | - if ( $wgCapitalLinks ) { |
39 | | - global $wgContLang; |
40 | | - return $namespace . $wgContLang->ucfirst( $title->getPartialURL() ); |
41 | | - } else { |
42 | | - return $namespace . $title->getPartialURL(); |
43 | | - } |
44 | | - } |
45 | | - |
46 | | - /** |
47 | | - * A very similar function to titleURLString(), to get the |
48 | | - * non-URL-encoded title string |
49 | | - */ |
50 | | - static function titleString( $title ) { |
51 | | - global $wgCapitalLinks; |
52 | | - |
53 | | - $namespace = $title->getNsText(); |
54 | | - if ( '' != $namespace ) { |
55 | | - $namespace .= ':'; |
56 | | - } |
57 | | - if ( $wgCapitalLinks ) { |
58 | | - global $wgContLang; |
59 | | - return $namespace . $wgContLang->ucfirst( $title->getText() ); |
60 | | - } else { |
61 | | - return $namespace . $title->getText(); |
62 | | - } |
63 | | - } |
64 | | - |
65 | | - /** |
66 | | - * Gets the forms specified, if any, of either type "default form", |
67 | | - * "alternate form", or "default form for page", for a specific page |
68 | | - * (which should be a category, property, or namespace page) |
69 | | - */ |
70 | | - static function getFormsThatPagePointsTo( $page_name, $page_namespace, $prop_smw_id, $backup_prop_smw_id, $prop_id ) { |
71 | | - if ( $page_name == NULL ) |
72 | | - return array(); |
73 | | - |
74 | | - global $sfgContLang; |
75 | | - // produce a useful error message if SMW isn't installed |
76 | | - if ( ! function_exists( 'smwfGetStore' ) ) |
77 | | - die( "ERROR: <a href=\"http://semantic-mediawiki.org\">Semantic MediaWiki</a> must be installed for Semantic Forms to run!" ); |
78 | | - $store = smwfGetStore(); |
79 | | - $title = Title::makeTitleSafe( $page_namespace, $page_name ); |
80 | | - $property = SMWPropertyValue::makeProperty( $prop_smw_id ); |
81 | | - $res = $store->getPropertyValues( $title, $property ); |
82 | | - $form_names = array(); |
83 | | - foreach ( $res as $wiki_page_value ) { |
84 | | - $form_title = $wiki_page_value->getTitle(); |
85 | | - if ( ! is_null( $form_title ) ) { |
86 | | - $form_names[] = $form_title->getText(); |
87 | | - } |
88 | | - } |
89 | | - // if we're using a non-English language, check for the English string as well |
90 | | - if ( ! class_exists( 'SF_LanguageEn' ) || ! $sfgContLang instanceof SF_LanguageEn ) { |
91 | | - $backup_property = SMWPropertyValue::makeProperty( $backup_prop_smw_id ); |
92 | | - $res = $store->getPropertyValues( $title, $backup_property ); |
93 | | - foreach ( $res as $wiki_page_value ) |
94 | | - $form_names[] = $wiki_page_value->getTitle()->getText(); |
95 | | - } |
96 | | - return $form_names; |
97 | | - } |
98 | | - |
99 | | - /** |
100 | | - * Helper function for formEditLink() - gets the 'default form' and |
101 | | - * 'alternate form' properties for a page, and creates the |
102 | | - * corresponding Special:FormEdit link, if any such properties are |
103 | | - * defined |
104 | | - */ |
105 | | - static function getFormEditLinkForPage( $target_page_title, $page_name, $page_namespace ) { |
106 | | - $default_forms = self::getFormsThatPagePointsTo( $page_name, $page_namespace, '_SF_DF', '_SF_DF_BACKUP', SF_SP_HAS_DEFAULT_FORM ); |
107 | | - $alt_forms = self::getFormsThatPagePointsTo( $page_name, $page_namespace, '_SF_AF', '_SF_AF_BACKUP', SF_SP_HAS_ALTERNATE_FORM ); |
108 | | - if ( ( count( $default_forms ) == 0 ) && ( count( $alt_forms ) == 0 ) ) |
109 | | - return null; |
110 | | - $fe = SpecialPage::getPage( 'FormEdit' ); |
111 | | - $fe_url = $fe->getTitle()->getLocalURL(); |
112 | | - if ( count( $default_forms ) > 0 ) |
113 | | - $form_edit_url = $fe_url . "/" . $default_forms[0] . "/" . self::titleURLString( $target_page_title ); |
114 | | - else |
115 | | - $form_edit_url = $fe_url . "/" . self::titleURLString( $target_page_title ); |
116 | | - foreach ( $alt_forms as $i => $alt_form ) { |
117 | | - $form_edit_url .= ( strpos( $form_edit_url, "?" ) ) ? "&" : "?"; |
118 | | - $form_edit_url .= "alt_form[$i]=$alt_form"; |
119 | | - } |
120 | | - return $form_edit_url; |
121 | | - } |
122 | | - |
123 | | - /** |
124 | | - * Sets the URL for form-based creation of a nonexistent (broken-linked, |
125 | | - * AKA red-linked) page, for MediaWiki 1.13 |
126 | | - */ |
127 | | - static function setBrokenLink_1_13( &$linker, $title, $query, &$u, &$style, &$prefix, &$text, &$inside, &$trail ) { |
128 | | - if ( self::createLinkedPage( $title ) ) { |
129 | | - return true; |
130 | | - } |
131 | | - $link = self::formEditLink( $title ); |
132 | | - if ( $link != '' ) |
133 | | - $u = $link; |
134 | | - return true; |
135 | | - } |
136 | | - |
137 | | - /** |
138 | | - * Sets the URL for form-based creation of a nonexistent (broken-linked, |
139 | | - * AKA red-linked) page |
140 | | - */ |
141 | | - static function setBrokenLink( $linker, $target, $options, $text, &$attribs, &$ret ) { |
142 | | - if ( in_array( 'broken', $options ) ) { |
143 | | - if ( self::createLinkedPage( $target ) ) { |
144 | | - return true; |
145 | | - } |
146 | | - $link = self::formEditLink( $target ); |
147 | | - if ( $link != '' ) { |
148 | | - $attribs['href'] = $link; |
149 | | - } |
150 | | - } |
151 | | - return true; |
152 | | - } |
153 | | - |
154 | | - /** |
155 | | - * Automatically creates a page that's red-linked from the page being |
156 | | - * viewed, if there's a property pointing from anywhere to that page |
157 | | - * that's defined with the 'Creates pages with form' special property |
158 | | - */ |
159 | | - static function createLinkedPage( $title ) { |
160 | | - // if we're in a 'special' page, just exit - this is to prevent |
161 | | - // constant additions being made from the 'Special:RecentChanges' |
162 | | - // page, which shows pages that were previously deleted as red |
163 | | - // links, even if they've since been recreated. The same might |
164 | | - // hold true for other special pages. |
165 | | - global $wgTitle; |
166 | | - if ( $wgTitle->getNamespace() == NS_SPECIAL ) |
167 | | - return false; |
168 | | - |
169 | | - $store = smwfGetStore(); |
170 | | - $title_text = self::titleString( $title ); |
171 | | - $value = SMWDataValueFactory::newTypeIDValue( '_wpg', $title_text ); |
172 | | - $incoming_properties = $store->getInProperties( $value ); |
173 | | - foreach ( $incoming_properties as $property ) { |
174 | | - $property_name = $property->getWikiValue(); |
175 | | - if ( empty( $property_name ) ) continue; |
176 | | - $property_title = Title::makeTitleSafe( SMW_NS_PROPERTY, $property_name ); |
177 | | - $auto_create_forms = self::getFormsThatPagePointsTo( $property_name, SMW_NS_PROPERTY, '_SF_CP', '_SF_CP_BACKUP', SF_SP_CREATES_PAGES_WITH_FORM ); |
178 | | - if ( count( $auto_create_forms ) > 0 ) { |
179 | | - global $sfgFormPrinter; |
180 | | - $form_name = $auto_create_forms[0]; |
181 | | - $form_title = Title::makeTitleSafe( SF_NS_FORM, $form_name ); |
182 | | - $form_article = new Article( $form_title ); |
183 | | - $form_definition = $form_article->getContent(); |
184 | | - list ( $form_text, $javascript_text, $data_text, $form_page_title, $generated_page_name ) = |
185 | | - $sfgFormPrinter->formHTML( $form_definition, false, false, null, null, 'Some very long page name that will hopefully never get created ABCDEF123', null ); |
186 | | - $params = array(); |
187 | | - global $wgUser; |
188 | | - $params['user_id'] = $wgUser->getId(); |
189 | | - $params['page_text'] = $data_text; |
190 | | - $job = new SFCreatePageJob( $title, $params ); |
191 | | - Job::batchInsert( array( $job ) ); |
192 | | - |
193 | | - return true; |
194 | | - } |
195 | | - } |
196 | | - |
197 | | - return false; |
198 | | - } |
199 | | - |
200 | | - /** |
201 | | - * Returns the URL for the Special:FormEdit page for a specific page, |
202 | | - * given its default and alternate form(s) - we can't just point to |
203 | | - * '&action=formedit', because that one doesn't reflect alternate forms |
204 | | - */ |
205 | | - static function formEditLink( $title ) { |
206 | | - // get all properties pointing to this page, and if |
207 | | - // getFormEditLinkForPage() returns a value with any of |
208 | | - // them, return that |
209 | | - |
210 | | - // produce a useful error message if SMW isn't installed |
211 | | - if ( ! function_exists( 'smwfGetStore' ) ) |
212 | | - die( "ERROR: <a href=\"http://semantic-mediawiki.org\">Semantic MediaWiki</a> must be installed for Semantic Forms to run!" ); |
213 | | - $store = smwfGetStore(); |
214 | | - $title_text = self::titleString( $title ); |
215 | | - $value = SMWDataValueFactory::newTypeIDValue( '_wpg', $title_text ); |
216 | | - $incoming_properties = $store->getInProperties( $value ); |
217 | | - foreach ( $incoming_properties as $property ) { |
218 | | - $property_title = $property->getWikiValue(); |
219 | | - if ( $form_edit_link = self::getFormEditLinkForPage( $title, $property_title, SMW_NS_PROPERTY ) ) { |
220 | | - return $form_edit_link; |
221 | | - } |
222 | | - } |
223 | | - |
224 | | - // if that didn't work, check if this page's namespace |
225 | | - // has a default form specified |
226 | | - $namespace = $title->getNsText(); |
227 | | - if ( '' === $namespace ) { |
228 | | - // if it's in the main (blank) namespace, check for the |
229 | | - // file named with the word for "Main" in this language |
230 | | - wfLoadExtensionMessages( 'SemanticForms' ); |
231 | | - $namespace = wfMsgForContent( 'sf_blank_namespace' ); |
232 | | - } |
233 | | - if ( $form_edit_link = self::getFormEditLinkForPage( $title, $namespace, NS_PROJECT ) ) { |
234 | | - return $form_edit_link; |
235 | | - } |
236 | | - // if nothing found still, return null |
237 | | - return null; |
238 | | - } |
239 | | - |
240 | | - /** |
241 | | - * Helper function - gets names of categories for a page; |
242 | | - * based on Title::getParentCategories(), but simpler |
243 | | - * - this function doubles as a function to get all categories on |
244 | | - * the site, if no article is specified |
245 | | - */ |
246 | | - static function getCategoriesForArticle( $article = NULL ) { |
247 | | - $categories = array(); |
248 | | - $db = wfGetDB( DB_SLAVE ); |
249 | | - $conditions = null; |
250 | | - if ( $article != NULL ) { |
251 | | - $titlekey = $article->mTitle->getArticleId(); |
252 | | - $conditions = "cl_from='$titlekey'"; |
253 | | - } |
254 | | - $res = $db->select( $db->tableName( 'categorylinks' ), |
255 | | - 'distinct cl_to', $conditions, __METHOD__ ); |
256 | | - if ( $db->numRows( $res ) > 0 ) { |
257 | | - while ( $row = $db->fetchRow( $res ) ) { |
258 | | - $categories[] = $row[0]; |
259 | | - } |
260 | | - } |
261 | | - $db->freeResult( $res ); |
262 | | - return $categories; |
263 | | - } |
264 | | - |
265 | | - /** |
266 | | - * Get the form used to edit this article - either: |
267 | | - * - the default form the page itself, if there is one; or |
268 | | - * - the default form for a category that this article belongs to, |
269 | | - * if there is one; or |
270 | | - * - the default form for the article's namespace, if there is one |
271 | | - */ |
272 | | - static function getFormsForArticle( $obj ) { |
273 | | - // see if the page itself has a default form (or forms), and |
274 | | - // return it/them if so |
275 | | - $default_forms = self::getFormsThatPagePointsTo( $obj->mTitle->getText(), $obj->mTitle->getNamespace(), '_SF_PDF', '_SF_PDF_BACKUP', SF_SP_PAGE_HAS_DEFAULT_FORM ); |
276 | | - if ( count( $default_forms ) > 0 ) |
277 | | - return $default_forms; |
278 | | - // if this is not a category page, look for a default form |
279 | | - // for its parent categories |
280 | | - $namespace = $obj->mTitle->getNamespace(); |
281 | | - if ( NS_CATEGORY !== $namespace ) { |
282 | | - $default_forms = array(); |
283 | | - $categories = self::getCategoriesForArticle( $obj ); |
284 | | - foreach ( $categories as $category ) { |
285 | | - $default_forms = array_merge( $default_forms, self::getFormsThatPagePointsTo( $category, NS_CATEGORY, '_SF_DF', '_SF_DF_BACKUP', SF_SP_HAS_DEFAULT_FORM ) ); |
286 | | - } |
287 | | - if ( count( $default_forms ) > 0 ) |
288 | | - return $default_forms; |
289 | | - } |
290 | | - // if we're still here, just return the default form for the |
291 | | - // namespace, which may well be null |
292 | | - if ( NS_MAIN === $namespace ) { |
293 | | - // if it's in the main (blank) namespace, check for the |
294 | | - // file named with the word for "Main" in this language |
295 | | - wfLoadExtensionMessages( 'SemanticForms' ); |
296 | | - $namespace_label = wfMsgForContent( 'sf_blank_namespace' ); |
297 | | - } else { |
298 | | - global $wgContLang; |
299 | | - $namespace_labels = $wgContLang->getNamespaces(); |
300 | | - $namespace_label = $namespace_labels[$namespace]; |
301 | | - } |
302 | | - $default_forms = self::getFormsThatPagePointsTo( $namespace_label, NS_PROJECT, '_SF_DF', '_SF_DF_BACKUP', SF_SP_HAS_DEFAULT_FORM ); |
303 | | - return $default_forms; |
304 | | - } |
305 | | - |
306 | | -} |
Index: trunk/extensions/SemanticForms/includes/SF_FormClasses.php |
— | — | @@ -0,0 +1,212 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Two classes - SFForm and SFTemplateInForm - that represent a user-defined |
| 5 | + * form and a template contained within that form, respectively. |
| 6 | + * |
| 7 | + * @author Yaron Koren |
| 8 | + */ |
| 9 | + |
| 10 | +class SFForm { |
| 11 | + var $form_name; |
| 12 | + var $templates; |
| 13 | + |
| 14 | + static function create( $form_name, $templates ) { |
| 15 | + $form = new SFForm(); |
| 16 | + $form->form_name = ucfirst( str_replace( '_', ' ', $form_name ) ); |
| 17 | + $form->templates = $templates; |
| 18 | + return $form; |
| 19 | + } |
| 20 | + |
| 21 | + function creationHTML() { |
| 22 | + $text = ""; |
| 23 | + foreach ( $this->templates as $i => $ft ) { |
| 24 | + $text .= $ft->creationHTML( $i ); |
| 25 | + } |
| 26 | + return $text; |
| 27 | + } |
| 28 | + |
| 29 | + function createMarkup() { |
| 30 | + $title = Title::makeTitle( SF_NS_FORM, $this->form_name ); |
| 31 | + $fs = SpecialPage::getPage( 'FormStart' ); |
| 32 | + $form_start_url = SFLinkUtils::titleURLString( $fs->getTitle() ) . "/" . $title->getPartialURL(); |
| 33 | + $form_description = wfMsgForContent( 'sf_form_docu', $this->form_name, $form_start_url ); |
| 34 | + $form_input = "{{#forminput:form=" . $this->form_name . "}}\n"; |
| 35 | + $text = <<<END |
| 36 | +<noinclude> |
| 37 | +$form_description |
| 38 | + |
| 39 | + |
| 40 | +$form_input |
| 41 | +</noinclude><includeonly> |
| 42 | +<div id="wikiPreview" style="display: none; padding-bottom: 25px; margin-bottom: 25px; border-bottom: 1px solid #AAAAAA;"></div> |
| 43 | + |
| 44 | +END; |
| 45 | + foreach ( $this->templates as $template ) { |
| 46 | + $text .= $template->createMarkup() . "\n"; |
| 47 | + } |
| 48 | + $free_text_label = wfMsgForContent( 'sf_form_freetextlabel' ); |
| 49 | + $text .= <<<END |
| 50 | +'''$free_text_label:''' |
| 51 | + |
| 52 | +{{{standard input|free text|rows=10}}} |
| 53 | + |
| 54 | + |
| 55 | +{{{standard input|summary}}} |
| 56 | + |
| 57 | +{{{standard input|minor edit}}} {{{standard input|watch}}} |
| 58 | + |
| 59 | +{{{standard input|save}}} {{{standard input|preview}}} {{{standard input|changes}}} {{{standard input|cancel}}} |
| 60 | +</includeonly> |
| 61 | + |
| 62 | +END; |
| 63 | + |
| 64 | + return $text; |
| 65 | + } |
| 66 | + |
| 67 | +} |
| 68 | + |
| 69 | +class SFTemplateInForm { |
| 70 | + var $template_name; |
| 71 | + var $label; |
| 72 | + var $allow_multiple; |
| 73 | + var $max_allowed; |
| 74 | + var $fields; |
| 75 | + |
| 76 | + function getAllFields() { |
| 77 | + global $wgContLang; |
| 78 | + $template_fields = array(); |
| 79 | + $field_names_array = array(); |
| 80 | + |
| 81 | + // Get the fields of the template, both semantic and otherwise, by parsing |
| 82 | + // the text of the template. |
| 83 | + // The way this works is that fields are found and then stored in an |
| 84 | + // array based on their location in the template text, so that they |
| 85 | + // can be returned in the order in which they appear in the template, even |
| 86 | + // though they were found in a different order. |
| 87 | + // Some fields can be found more than once (especially if they're part |
| 88 | + // of an "#if" statement), so they're only recorded the first time they're |
| 89 | + // found. Also, every field gets replaced with a string of x's after |
| 90 | + // being found, so it doesn't interfere with future parsing. |
| 91 | + $template_title = Title::makeTitleSafe( NS_TEMPLATE, $this->template_name ); |
| 92 | + $template_article = null; |
| 93 | + if ( isset( $template_title ) ) $template_article = new Article( $template_title ); |
| 94 | + if ( isset( $template_article ) ) { |
| 95 | + $template_text = $template_article->getContent(); |
| 96 | + // ignore 'noinclude' sections and 'includeonly' tags |
| 97 | + $template_text = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $template_text ); |
| 98 | + $template_text = strtr( $template_text, array( '<includeonly>' => '', '</includeonly>' => '' ) ); |
| 99 | + |
| 100 | + // first, look for "arraymap" parser function calls that map a |
| 101 | + // property onto a list |
| 102 | + if ( preg_match_all( '/{{#arraymap:{{{([^|}]*:?[^|}]*)[^\[]*\[\[([^:=]*:?[^:=]*)(:[:=])/mis', $template_text, $matches ) ) { |
| 103 | + // this is a two-dimensional array; we need the last three of the four |
| 104 | + // sub-arrays; we also have to remove redundant values |
| 105 | + foreach ( $matches[1] as $i => $field_name ) { |
| 106 | + $semantic_property = $matches[2][$i]; |
| 107 | + $full_field_text = $matches[0][$i]; |
| 108 | + if ( ! in_array( $field_name, $field_names_array ) ) { |
| 109 | + $template_field = SFTemplateField::create( $field_name, $wgContLang->ucfirst( $field_name ) ); |
| 110 | + $template_field->setSemanticProperty( $semantic_property ); |
| 111 | + $template_field->is_list = true; |
| 112 | + $cur_pos = stripos( $template_text, $full_field_text ); |
| 113 | + $template_fields[$cur_pos] = $template_field; |
| 114 | + $field_names_array[] = $field_name; |
| 115 | + $replacement = str_repeat( "x", strlen( $full_field_text ) ); |
| 116 | + $template_text = str_replace( $full_field_text, $replacement, $template_text ); |
| 117 | + } |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + // second, look for normal property calls |
| 122 | + if ( preg_match_all( '/\[\[([^:=]*:*?[^:=]*)(:[:=]){{{([^\]\|}]*).*?\]\]/mis', $template_text, $matches ) ) { |
| 123 | + // this is a two-dimensional array; we need the last three of the four |
| 124 | + // sub-arrays; we also have to remove redundant values |
| 125 | + foreach ( $matches[1] as $i => $semantic_property ) { |
| 126 | + $field_name = $matches[3][$i]; |
| 127 | + $full_field_text = $matches[0][$i]; |
| 128 | + if ( ! in_array( $field_name, $field_names_array ) ) { |
| 129 | + $template_field = SFTemplateField::create( $field_name, $wgContLang->ucfirst( $field_name ) ); |
| 130 | + $template_field->setSemanticProperty( $semantic_property ); |
| 131 | + $cur_pos = stripos( $template_text, $full_field_text ); |
| 132 | + $template_fields[$cur_pos] = $template_field; |
| 133 | + $field_names_array[] = $field_name; |
| 134 | + $replacement = str_repeat( "x", strlen( $full_field_text ) ); |
| 135 | + $template_text = str_replace( $full_field_text, $replacement, $template_text ); |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + // finally, get any non-semantic fields defined |
| 141 | + if ( preg_match_all( '/{{{([^|}]*)/mis', $template_text, $matches ) ) { |
| 142 | + foreach ( $matches[1] as $i => $field_name ) { |
| 143 | + $full_field_text = $matches[0][$i]; |
| 144 | + if ( ( $full_field_text != '' ) && ( ! in_array( $field_name, $field_names_array ) ) ) { |
| 145 | + $cur_pos = stripos( $template_text, $full_field_text ); |
| 146 | + $template_fields[$cur_pos] = SFTemplateField::create( $field_name, $wgContLang->ucfirst( $field_name ) ); |
| 147 | + $field_names_array[] = $field_name; |
| 148 | + } |
| 149 | + } |
| 150 | + } |
| 151 | + } |
| 152 | + ksort( $template_fields ); |
| 153 | + return $template_fields; |
| 154 | + } |
| 155 | + |
| 156 | + static function create( $name, $label, $allow_multiple, $max_allowed = null ) { |
| 157 | + $tif = new SFTemplateInForm(); |
| 158 | + $tif->template_name = str_replace( '_', ' ', $name ); |
| 159 | + $tif->fields = array(); |
| 160 | + $fields = $tif->getAllFields(); |
| 161 | + $field_num = 0; |
| 162 | + foreach ( $fields as $field ) { |
| 163 | + $tif->fields[] = SFFormField::create( $field_num++, $field ); |
| 164 | + } |
| 165 | + $tif->label = $label; |
| 166 | + $tif->allow_multiple = $allow_multiple; |
| 167 | + $tif->max_allowed = $max_allowed; |
| 168 | + return $tif; |
| 169 | + } |
| 170 | + |
| 171 | + function creationHTML( $template_num ) { |
| 172 | + $checked_str = ( $this->allow_multiple ) ? "checked" : ""; |
| 173 | + $template_str = wfMsg( 'sf_createform_template' ); |
| 174 | + $template_label_input = wfMsg( 'sf_createform_templatelabelinput' ); |
| 175 | + $allow_multiple_text = wfMsg( 'sf_createform_allowmultiple' ); |
| 176 | + $text = <<<END |
| 177 | + <input type="hidden" name="template_$template_num" value="$this->template_name"> |
| 178 | + <div class="templateForm"> |
| 179 | + <h2>$template_str '$this->template_name'</h2> |
| 180 | + <p>$template_label_input <input size=25 name="label_$template_num" value="$this->label"></p> |
| 181 | + <p><input type="checkbox" name="allow_multiple_$template_num" $checked_str> $allow_multiple_text</p> |
| 182 | + <hr> |
| 183 | + |
| 184 | +END; |
| 185 | + foreach ( $this->fields as $field ) { |
| 186 | + $text .= $field->creationHTML( $template_num ); |
| 187 | + } |
| 188 | + $text .= ' <p><input type="submit" name="del_' . $template_num . |
| 189 | + '" value="' . wfMsg( 'sf_createform_removetemplate' ) . '"></p>' . "\n"; |
| 190 | + $text .= " </div>\n"; |
| 191 | + return $text; |
| 192 | + } |
| 193 | + |
| 194 | + function createMarkup() { |
| 195 | + $text = ""; |
| 196 | + $text .= "{{{for template|" . $this->template_name; |
| 197 | + if ( $this->allow_multiple ) |
| 198 | + $text .= "|multiple"; |
| 199 | + if ( $this->label != '' ) |
| 200 | + $text .= "|label=" . $this->label; |
| 201 | + $text .= "}}}\n"; |
| 202 | + // for now, HTML for templates differs for multiple-instance templates; |
| 203 | + // this may change if handling of form definitions gets more sophisticated |
| 204 | + if ( ! $this->allow_multiple ) { $text .= "{| class=\"formtable\"\n"; } |
| 205 | + foreach ( $this->fields as $i => $field ) { |
| 206 | + $is_last_field = ( $i == count( $this->fields ) - 1 ); |
| 207 | + $text .= $field->createMarkup( $this->allow_multiple, $is_last_field ); |
| 208 | + } |
| 209 | + if ( ! $this->allow_multiple ) { $text .= "|}\n"; } |
| 210 | + $text .= "{{{end template}}}\n"; |
| 211 | + return $text; |
| 212 | + } |
| 213 | +} |
Property changes on: trunk/extensions/SemanticForms/includes/SF_FormClasses.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 214 | + native |
Index: trunk/extensions/SemanticForms/includes/SF_FormUtils.php |
— | — | @@ -0,0 +1,1108 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Javascript- and HTML-creation utilities for the display of a form |
| 5 | + * |
| 6 | + * @author Yaron Koren |
| 7 | + * @author Jeffrey Stuckman |
| 8 | + * @author Harold Solbrig |
| 9 | + * @author Eugene Mednikov |
| 10 | + */ |
| 11 | + |
| 12 | +class SFFormUtils { |
| 13 | + |
| 14 | + static function chooserJavascript() { |
| 15 | + $javascript_text = <<<END |
| 16 | +<script type="text/javascript">/* <![CDATA[ */ |
| 17 | + |
| 18 | +function updatechooserbutton(f,n) |
| 19 | +{ |
| 20 | + document.getElementById(n).disabled = (f.options[f.selectedIndex].value=="invalid"); |
| 21 | +} |
| 22 | + |
| 23 | +function addInstanceFromChooser(chooserid) |
| 24 | +{ |
| 25 | + var chooser = document.getElementById(chooserid); |
| 26 | + var optionstring = chooser.options[chooser.selectedIndex].value; |
| 27 | + var pos = optionstring.indexOf(","); |
| 28 | + var tabindex = optionstring.substr(0,pos); |
| 29 | + var chooservalue = optionstring.substr(pos+1); |
| 30 | + addInstance('starter_' + chooservalue, 'main_' + chooservalue, parseInt(tabindex)); |
| 31 | +} |
| 32 | + |
| 33 | +//The fieldset containing the given element was just updated. If the fieldset is associated with a chooser, |
| 34 | +//ensure that the fieldset is hidden if and only if there are no template instances inside. |
| 35 | +function hideOrShowFieldset(element) |
| 36 | +{ |
| 37 | + //Find fieldset |
| 38 | + while (element.tagName.toLowerCase() != "fieldset") |
| 39 | + element = element.parentNode; |
| 40 | + //Bail out if fieldset is not part of chooser |
| 41 | + if (!element.getAttribute("haschooser")) |
| 42 | + return; |
| 43 | + //Now look for "input" or "select" tags that don't look like they're part of the starter template |
| 44 | + var inputs = element.getElementsByTagName("input"); |
| 45 | + var x; |
| 46 | + var show = false; |
| 47 | + for (x=0;x<inputs.length;x++) |
| 48 | + { |
| 49 | + if (inputs[x].type=="text" && inputs[x].name.indexOf("[num]") == -1) |
| 50 | + show = true; |
| 51 | + } |
| 52 | + var selects = element.getElementsByTagName("select"); |
| 53 | + for (x=0;x<selects.length;x++) |
| 54 | + { |
| 55 | + if (selects[x].name.indexOf("[num]") == -1) |
| 56 | + show = true; |
| 57 | + } |
| 58 | + //Now show or hide fieldset |
| 59 | + element.style.display = (show?"block":"none"); |
| 60 | +} |
| 61 | +/* ]]> */ </script> |
| 62 | + |
| 63 | +END; |
| 64 | + return $javascript_text; |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * All the Javascript calls to validate both the type of each |
| 69 | + * form field and their presence, for mandatory fields |
| 70 | + */ |
| 71 | + static function validationJavascript() { |
| 72 | + global $sfgJSValidationCalls; |
| 73 | + |
| 74 | + $form_errors_header = Xml::escapeJsString( wfMsg( 'sf_formerrors_header' ) ); |
| 75 | + $blank_error_str = Xml::escapeJsString( wfMsg( 'sf_blank_error' ) ); |
| 76 | + $bad_url_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_url_error' ) ); |
| 77 | + $bad_email_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_email_error' ) ); |
| 78 | + $bad_number_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_number_error' ) ); |
| 79 | + $bad_integer_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_integer_error' ) ); |
| 80 | + $bad_date_error_str = Xml::escapeJsString( wfMsg( 'sf_bad_date_error' ) ); |
| 81 | + |
| 82 | + $javascript_text = <<<END |
| 83 | + |
| 84 | +function validate_mandatory_field(field_id, info_id) { |
| 85 | + field = document.getElementById(field_id); |
| 86 | + if (field.value.replace(/\s+/, '') == '') { |
| 87 | + infobox = document.getElementById(info_id); |
| 88 | + infobox.innerHTML = "$blank_error_str"; |
| 89 | + return false; |
| 90 | + } else { |
| 91 | + return true; |
| 92 | + } |
| 93 | +} |
| 94 | + |
| 95 | +// special handling for radiobuttons, because what's being checked |
| 96 | +// is the first radiobutton, which has value of "None" |
| 97 | +function validate_mandatory_radiobutton(none_button_id, info_id) { |
| 98 | + none_button = document.getElementById(none_button_id); |
| 99 | + if (none_button && none_button.checked) { |
| 100 | + infobox = document.getElementById(info_id); |
| 101 | + infobox.innerHTML = "$blank_error_str"; |
| 102 | + return false; |
| 103 | + } else { |
| 104 | + return true; |
| 105 | + } |
| 106 | +} |
| 107 | + |
| 108 | +function validate_mandatory_checkboxes(field_id, info_id) { |
| 109 | + elems = document.getElementsByTagName("*"); |
| 110 | + var all_fields_unchecked = true; |
| 111 | + for (var i = 0; i < elems.length; i++) { |
| 112 | + if (elems[i].id == field_id) { |
| 113 | + if (elems[i].checked) { |
| 114 | + all_fields_unchecked = false; |
| 115 | + } |
| 116 | + } |
| 117 | + } |
| 118 | + if (all_fields_unchecked) { |
| 119 | + infobox = document.getElementById(info_id); |
| 120 | + infobox.innerHTML = "$blank_error_str"; |
| 121 | + return false; |
| 122 | + } else { |
| 123 | + return true; |
| 124 | + } |
| 125 | +} |
| 126 | + |
| 127 | +// validate a mandatory field that exists across multiple instances of |
| 128 | +// a template - we have to find each one, matching on the pattern of its |
| 129 | +// ID, and validate it |
| 130 | +function validate_multiple_mandatory_fields(field_num) { |
| 131 | + var num_errors = 0; |
| 132 | + elems = document.getElementsByTagName("*"); |
| 133 | + var field_pattern = new RegExp('input_(.*)_' + field_num); |
| 134 | + for (var i = 0; i < elems.length; i++) { |
| 135 | + id = elems[i].id; |
| 136 | + if (matches = field_pattern.exec(id)) { |
| 137 | + instance_num = matches[1]; |
| 138 | + var input_name = "input_" + instance_num + "_" + field_num; |
| 139 | + var info_name = "info_" + instance_num + "_" + field_num; |
| 140 | + if (! validate_mandatory_field(input_name, info_name)) { |
| 141 | + num_errors += 1; |
| 142 | + } |
| 143 | + } |
| 144 | + } |
| 145 | + return (num_errors == 0); |
| 146 | +} |
| 147 | + |
| 148 | +function validate_field_type(field_id, type, info_id) { |
| 149 | + field = document.getElementById(field_id); |
| 150 | + if (type != 'date' && field.value == '') { |
| 151 | + return true; |
| 152 | + } else { |
| 153 | + if (type == 'URL') { |
| 154 | + // code borrowed from http://snippets.dzone.com/posts/show/452 |
| 155 | + var url_regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; |
| 156 | + if (url_regexp.test(field.value)) { |
| 157 | + return true; |
| 158 | + } else { |
| 159 | + infobox = document.getElementById(info_id); |
| 160 | + infobox.innerHTML = "$bad_url_error_str"; |
| 161 | + return false; |
| 162 | + } |
| 163 | + } else if (type == 'email') { |
| 164 | + // code borrowed from http://javascript.internet.com/forms/email-validation---basic.html |
| 165 | + var email_regexp = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,6})+$/; |
| 166 | + if (email_regexp.test(field.value)) { |
| 167 | + return true; |
| 168 | + } else { |
| 169 | + infobox = document.getElementById(info_id); |
| 170 | + infobox.innerHTML = "$bad_email_error_str"; |
| 171 | + return false; |
| 172 | + } |
| 173 | + } else if (type == 'number') { |
| 174 | + if (field.value.match(/^\-?[\d\.,]+$/)) { |
| 175 | + return true; |
| 176 | + } else { |
| 177 | + infobox = document.getElementById(info_id); |
| 178 | + infobox.innerHTML = "$bad_number_error_str"; |
| 179 | + return false; |
| 180 | + } |
| 181 | + } else if (type == 'date') { |
| 182 | + // validate only if day and year fields are both filled in |
| 183 | + day_field = document.getElementById(field_id + "_day"); |
| 184 | + year_field = document.getElementById(field_id + "_year"); |
| 185 | + if (day_field.value == '' || year_field.value == '') { |
| 186 | + return true; |
| 187 | + } else if (day_field.value.match(/^\d+$/) && |
| 188 | + day_field.value <= 31) { |
| 189 | + // no year validation, since it can also include |
| 190 | + // 'BC' and possibly other non-number strings |
| 191 | + return true; |
| 192 | + } else { |
| 193 | + infobox = document.getElementById(info_id); |
| 194 | + infobox.innerHTML = "$bad_date_error_str"; |
| 195 | + return false; |
| 196 | + } |
| 197 | + } else { |
| 198 | + return true; |
| 199 | + } |
| 200 | + } |
| 201 | +} |
| 202 | + |
| 203 | +// same as validate_multiple_mandatory_fields(), but for type validation |
| 204 | +function validate_type_of_multiple_fields(field_num, type) { |
| 205 | + var num_errors = 0; |
| 206 | + elems = document.getElementsByTagName("*"); |
| 207 | + var field_pattern = new RegExp('input_(.*)_' + field_num); |
| 208 | + for (var i = 0; i < elems.length; i++) { |
| 209 | + id = elems[i].id; |
| 210 | + if (matches = field_pattern.exec(id)) { |
| 211 | + instance_num = matches[1]; |
| 212 | + var input_name = "input_" + instance_num + "_" + field_num; |
| 213 | + var info_name = "info_" + instance_num + "_" + field_num; |
| 214 | + if (! validate_field_type(input_name, type, info_name)) { |
| 215 | + num_errors += 1; |
| 216 | + } |
| 217 | + } |
| 218 | + } |
| 219 | + return (num_errors == 0); |
| 220 | +} |
| 221 | + |
| 222 | + |
| 223 | +function validate_all() { |
| 224 | + var num_errors = 0; |
| 225 | + |
| 226 | +END; |
| 227 | + foreach ( $sfgJSValidationCalls as $function_call ) { |
| 228 | + $javascript_text .= " if (! $function_call) num_errors += 1;\n"; |
| 229 | + } |
| 230 | + $javascript_text .= <<<END |
| 231 | + if (num_errors > 0) { |
| 232 | + // add error header, if it's not there already |
| 233 | + if (! document.getElementById("form_error_header")) { |
| 234 | + var errorMsg = document.createElement('div'); |
| 235 | + errorMsg.innerHTML = "<div id=\"form_error_header\" class=\"warningMessage\" style=\"font-size: medium\">$form_errors_header</div>"; |
| 236 | + document.getElementById("contentSub").appendChild(errorMsg); |
| 237 | + } |
| 238 | + scroll(0, 0); |
| 239 | + } |
| 240 | + return (num_errors == 0); |
| 241 | +} |
| 242 | + |
| 243 | +END; |
| 244 | + return $javascript_text; |
| 245 | + } |
| 246 | + |
| 247 | + static function instancesJavascript( $using_choosers ) { |
| 248 | + $remove_text = wfMsg( 'sf_formedit_remove' ); |
| 249 | + $javascript_text = <<<END |
| 250 | + |
| 251 | +var num_elements = 0; |
| 252 | + |
| 253 | +function addInstance(starter_div_id, main_div_id, tab_index) |
| 254 | +{ |
| 255 | + var starter_div = document.getElementById(starter_div_id); |
| 256 | + var main_div = document.getElementById(main_div_id); |
| 257 | + num_elements++; |
| 258 | + |
| 259 | + //Create the new instance |
| 260 | + var new_div = starter_div.cloneNode(true); |
| 261 | + var div_id = 'div_gen_' + num_elements; |
| 262 | + new_div.className = 'multipleTemplate'; |
| 263 | + new_div.id = div_id; |
| 264 | + new_div.style.display = 'block'; |
| 265 | + |
| 266 | + // make internal ID unique for the relevant divs and spans, and replace |
| 267 | + // the [num] index in the element names with an actual unique index |
| 268 | + var children = new_div.getElementsByTagName('*'); |
| 269 | + // this array is needed to counteract an IE bug |
| 270 | + var orig_children = starter_div.getElementsByTagName('*'); |
| 271 | + var x; |
| 272 | + for (x = 0; x < children.length; x++) { |
| 273 | + if (children[x].name) |
| 274 | + children[x].name = children[x].name.replace(/\[num\]/g, '[' + num_elements + ']'); |
| 275 | + if (children[x].id) |
| 276 | + children[x].id = children[x].id |
| 277 | + .replace(/input_/g, 'input_' + num_elements + '_') |
| 278 | + .replace(/info_/g, 'info_' + num_elements + '_') |
| 279 | + .replace(/div_/g, 'div_' + num_elements + '_'); |
| 280 | + if (children[x].href) |
| 281 | + children[x].href = children[x].href |
| 282 | + .replace(/input_/g, 'input_' + num_elements + '_'); |
| 283 | + // for dropdowns, copy over selectedIndex from original div, |
| 284 | + // to get around a bug in IE |
| 285 | + if (children[x].type == 'select-one') { |
| 286 | + children[x].selectedIndex = orig_children[x].selectedIndex; |
| 287 | + } |
| 288 | + } |
| 289 | + if (children[x]) { |
| 290 | + //We clone the last object |
| 291 | + if (children[x].href) { |
| 292 | + children[x].href = children[x].href |
| 293 | + .replace(/input_/g, 'input_' + num_elements + '_') |
| 294 | + .replace(/info_/g, 'info_' + num_elements + '_') |
| 295 | + .replace(/div_/g, 'div_' + num_elements + '_'); |
| 296 | + } |
| 297 | + } |
| 298 | + // Since we clone the first object and we have uploadable field |
| 299 | + // we must replace the input_ in order to let the printer return |
| 300 | + // the value into the right field |
| 301 | + //Create remove button |
| 302 | + var remove_button = document.createElement('input'); |
| 303 | + remove_button.type = 'button'; |
| 304 | + remove_button.value = "$remove_text"; |
| 305 | + remove_button.tabIndex = tab_index; |
| 306 | + remove_button.onclick = removeInstanceEventHandler(div_id); |
| 307 | + new_div.appendChild(remove_button); |
| 308 | + |
| 309 | + //Add the new instance |
| 310 | + main_div.appendChild(new_div); |
| 311 | + attachAutocompleteToAllFields(new_div); |
| 312 | + |
| 313 | + //In order to add the new instances in multiple floatBox (multiple templates) |
| 314 | + fb.tagAnchors(self.document); |
| 315 | + if ($using_choosers) { |
| 316 | + hideOrShowFieldset(new_div); |
| 317 | + } |
| 318 | +} |
| 319 | + |
| 320 | +function removeInstanceEventHandler(this_div_id) |
| 321 | +{ |
| 322 | + return function() { |
| 323 | + removeInstance(this_div_id); |
| 324 | + }; |
| 325 | +} |
| 326 | + |
| 327 | +function removeInstance(div_id) { |
| 328 | + var olddiv = document.getElementById(div_id); |
| 329 | + var parent = olddiv.parentNode; |
| 330 | + parent.removeChild(olddiv); |
| 331 | + if ($using_choosers) |
| 332 | + hideOrShowFieldset(parent); |
| 333 | +} |
| 334 | + |
| 335 | +END; |
| 336 | + return $javascript_text; |
| 337 | + } |
| 338 | + |
| 339 | + static function autocompletionJavascript() { |
| 340 | + global $wgScriptPath; |
| 341 | + |
| 342 | + $javascript_text = <<<END |
| 343 | +var autocompletemappings = new Array(); |
| 344 | +var autocompletestrings = new Array(); |
| 345 | +var autocompletedatatypes = new Array(); |
| 346 | + |
| 347 | +//Activate autocomplete functionality for every field on the document |
| 348 | +function attachAutocompleteToAllDocumentFields() |
| 349 | +{ |
| 350 | + var forms = document.getElementsByTagName("form"); |
| 351 | + var x; |
| 352 | + for (x = 0; x < forms.length; x++) { |
| 353 | + if (forms[x].name == "createbox") { |
| 354 | + attachAutocompleteToAllFields(forms[x]); |
| 355 | + } |
| 356 | + } |
| 357 | +} |
| 358 | + |
| 359 | +//Activate autocomplete functionality for every field under the specified element |
| 360 | +function attachAutocompleteToAllFields(base) |
| 361 | +{ |
| 362 | + var inputs = base.getElementsByTagName("input"); |
| 363 | + var y; |
| 364 | + for (y = 0; y < inputs.length; y++) { |
| 365 | + attachAutocompleteToField(inputs[y].id); |
| 366 | + } |
| 367 | + // don't forget the textareas |
| 368 | + inputs = base.getElementsByTagName("textarea"); |
| 369 | + for (y = 0; y < inputs.length; y++) { |
| 370 | + attachAutocompleteToField(inputs[y].id); |
| 371 | + } |
| 372 | +} |
| 373 | + |
| 374 | +//Activate autocomplete functionality for the specified field |
| 375 | +function attachAutocompleteToField(input_id) |
| 376 | +{ |
| 377 | + //Check input id for the proper format, to ensure this is for SF |
| 378 | + if (input_id.substr(0,6) == 'input_') |
| 379 | + { |
| 380 | + //Extract the field ID number from the input field |
| 381 | + var field_num = parseInt(input_id.substring(input_id.lastIndexOf('_') + 1, input_id.length),10); |
| 382 | + //Add the autocomplete string, if a mapping exists. |
| 383 | + var field_string = autocompletemappings[field_num]; |
| 384 | + if (field_string) { |
| 385 | + var div_id = input_id.replace(/input_/g, 'div_'); |
| 386 | + var field_values = new Array(); |
| 387 | + field_values = field_string.split(','); |
| 388 | + var delimiter = null; |
| 389 | + var data_source = field_values[0]; |
| 390 | + if (field_values[1] == 'list') { |
| 391 | + delimiter = ","; |
| 392 | + if (field_values[2] != null) { |
| 393 | + delimiter = field_values[2]; |
| 394 | + } |
| 395 | + } |
| 396 | + if (autocompletestrings[field_string] != null) { |
| 397 | + sf_autocomplete(input_id, div_id, autocompletestrings[field_string], null, null, delimiter, data_source); |
| 398 | + } else { |
| 399 | + sf_autocomplete(input_id, div_id, null, "{$wgScriptPath}/api.php", autocompletedatatypes[field_string], delimiter, data_source); |
| 400 | + } |
| 401 | + } |
| 402 | + } |
| 403 | +} |
| 404 | + |
| 405 | +YAHOO.util.Event.addListener(window, 'load', attachAutocompleteToAllDocumentFields); |
| 406 | + |
| 407 | +END; |
| 408 | + return $javascript_text; |
| 409 | + } |
| 410 | + |
| 411 | + static function hiddenFieldHTML( $input_name, $cur_value ) { |
| 412 | + $input = self::buttonHTML( array( |
| 413 | + 'type' => 'hidden', |
| 414 | + 'name' => $input_name, |
| 415 | + 'value' => $cur_value, |
| 416 | + ) ); |
| 417 | + return <<<END |
| 418 | + $input |
| 419 | + |
| 420 | +END; |
| 421 | + } |
| 422 | + |
| 423 | + /** |
| 424 | + * Add a hidden input for each field in the template call that's |
| 425 | + * not handled by the form itself |
| 426 | + */ |
| 427 | + static function unhandledFieldsHTML( $template_contents ) { |
| 428 | + $text = ""; |
| 429 | + foreach ( $template_contents as $key => $value ) { |
| 430 | + if ( $key != '' && !is_numeric( $key ) ) |
| 431 | + $text .= self::hiddenFieldHTML( "_unhandled_$key", $value ); |
| 432 | + } |
| 433 | + return $text; |
| 434 | + } |
| 435 | + |
| 436 | + /** |
| 437 | + * Add unhandled fields back into the template call that the form |
| 438 | + * generates, so that editing with a form will have no effect on them |
| 439 | + */ |
| 440 | + static function addUnhandledFields() { |
| 441 | + global $wgRequest; |
| 442 | + $additional_template_text = ""; |
| 443 | + foreach ( $wgRequest->getValues() as $key => $value ) { |
| 444 | + if ( substr( $key, 0, 11 ) == '_unhandled_' ) { |
| 445 | + $field_name = substr( $key, 11 ); |
| 446 | + $additional_template_text .= "|$field_name=$value\n"; |
| 447 | + } |
| 448 | + } |
| 449 | + return $additional_template_text; |
| 450 | + } |
| 451 | + |
| 452 | + /** |
| 453 | + * Helper function, for versions of MediaWiki that don't have |
| 454 | + * Xml::expandAttributes (i.e., before 1.13) |
| 455 | + */ |
| 456 | + static function expandAttributes( $attribs ) { |
| 457 | + if ( method_exists( 'Xml', 'expandAttributes' ) ) { |
| 458 | + return Xml::expandAttributes( $attribs ); |
| 459 | + } else { |
| 460 | + $out = ''; |
| 461 | + foreach ( $attribs as $name => $val ) |
| 462 | + $out .= " {$name}=\"" . Sanitizer::encodeAttribute( $val ) . '"'; |
| 463 | + return $out; |
| 464 | + } |
| 465 | + } |
| 466 | + |
| 467 | + static function summaryInputHTML( $is_disabled, $label = null, $attr = array() ) { |
| 468 | + global $sfgTabIndex; |
| 469 | + |
| 470 | + $sfgTabIndex++; |
| 471 | + if ( $label == null ) |
| 472 | + $label = wfMsg( 'summary' ); |
| 473 | + $disabled_text = ( $is_disabled ) ? " disabled" : ""; |
| 474 | + $attr = self::expandAttributes( $attr ); |
| 475 | + $text = <<<END |
| 476 | + <span id='wpSummaryLabel'><label for='wpSummary'>$label</label></span> |
| 477 | + <input tabindex="$sfgTabIndex" type='text' value="" name='wpSummary' id='wpSummary' maxlength='200' size='60'$disabled_text$attr/> |
| 478 | + |
| 479 | +END; |
| 480 | + return $text; |
| 481 | + } |
| 482 | + |
| 483 | + static function minorEditInputHTML( $is_disabled, $label = null, $attr = array() ) { |
| 484 | + global $sfgTabIndex; |
| 485 | + |
| 486 | + $sfgTabIndex++; |
| 487 | + $disabled_text = ( $is_disabled ) ? " disabled" : ""; |
| 488 | + if ( $label == null ) |
| 489 | + $label = wfMsgExt( 'minoredit', array( 'parseinline' ) ); |
| 490 | + $accesskey = wfMsg( 'accesskey-minoredit' ); |
| 491 | + $tooltip = wfMsg( 'tooltip-minoredit' ); |
| 492 | + $attr = self::expandAttributes( $attr ); |
| 493 | + $text = <<<END |
| 494 | + <input tabindex="$sfgTabIndex" type="checkbox" value="1" name="wpMinoredit" accesskey="$accesskey" id="wpMinoredit"$disabled_text$attr/> |
| 495 | + <label for="wpMinoredit" title="$tooltip">$label</label> |
| 496 | + |
| 497 | +END; |
| 498 | + return $text; |
| 499 | + } |
| 500 | + |
| 501 | + static function watchInputHTML( $is_disabled, $label = null, $attr = array() ) { |
| 502 | + global $sfgTabIndex, $wgUser, $wgTitle; |
| 503 | + |
| 504 | + $sfgTabIndex++; |
| 505 | + $checked_text = ""; |
| 506 | + $disabled_text = ( $is_disabled ) ? " disabled" : ""; |
| 507 | + // figure out if the checkbox should be checked - |
| 508 | + // this code borrowed from /includes/EditPage.php |
| 509 | + if ( $wgUser->getOption( 'watchdefault' ) ) { |
| 510 | + # Watch all edits |
| 511 | + $checked_text = " checked"; |
| 512 | + } elseif ( $wgUser->getOption( 'watchcreations' ) && !$wgTitle->exists() ) { |
| 513 | + # Watch creations |
| 514 | + $checked_text = " checked"; |
| 515 | + } elseif ( $wgTitle->userIsWatching() ) { |
| 516 | + # Already watched |
| 517 | + $checked_text = " checked"; |
| 518 | + } |
| 519 | + if ( $label == null ) |
| 520 | + $label = wfMsgExt( 'watchthis', array( 'parseinline' ) ); |
| 521 | + $accesskey = htmlspecialchars( wfMsg( 'accesskey-watch' ) ); |
| 522 | + $tooltip = htmlspecialchars( wfMsg( 'tooltip-watch' ) ); |
| 523 | + $attr = self::expandAttributes( $attr ); |
| 524 | + $text = <<<END |
| 525 | + <input tabindex="$sfgTabIndex" type="checkbox" name="wpWatchthis" accesskey="$accesskey" id='wpWatchthis'$checked_text$disabled_text$attr/> |
| 526 | + <label for="wpWatchthis" title="$tooltip">$label</label> |
| 527 | + |
| 528 | +END; |
| 529 | + return $text; |
| 530 | + } |
| 531 | + |
| 532 | + /** |
| 533 | + * Helper function to display a simple button |
| 534 | + */ |
| 535 | + static function buttonHTML( $values ) { |
| 536 | + $button_html = Xml::element( 'input', $values, '' ); |
| 537 | + return " $button_html\n"; |
| 538 | + } |
| 539 | + |
| 540 | + static function saveButtonHTML( $is_disabled, $label = null, $attr = array() ) { |
| 541 | + global $sfgTabIndex; |
| 542 | + |
| 543 | + $sfgTabIndex++; |
| 544 | + if ( $label == null ) |
| 545 | + $label = wfMsg( 'savearticle' ); |
| 546 | + $temp = $attr + array( |
| 547 | + 'id' => 'wpSave', |
| 548 | + 'name' => 'wpSave', |
| 549 | + 'type' => 'submit', |
| 550 | + 'tabindex' => $sfgTabIndex, |
| 551 | + 'value' => $label, |
| 552 | + 'accesskey' => wfMsg( 'accesskey-save' ), |
| 553 | + 'title' => wfMsg( 'tooltip-save' ), |
| 554 | + ); |
| 555 | + if ( $is_disabled ) { |
| 556 | + $temp['disabled'] = ''; |
| 557 | + } |
| 558 | + return self::buttonHTML( $temp ); |
| 559 | + } |
| 560 | + |
| 561 | + static function showPreviewButtonHTML( $is_disabled, $label = null, $attr = array() ) { |
| 562 | + global $sfgTabIndex; |
| 563 | + |
| 564 | + $sfgTabIndex++; |
| 565 | + if ( $label == null ) |
| 566 | + $label = wfMsg( 'showpreview' ); |
| 567 | + $temp = $attr + array( |
| 568 | + 'id' => 'wpPreview', |
| 569 | + 'name' => 'wpPreview', |
| 570 | + 'type' => 'submit', |
| 571 | + 'tabindex' => $sfgTabIndex, |
| 572 | + 'value' => $label, |
| 573 | + 'accesskey' => wfMsg( 'accesskey-preview' ), |
| 574 | + 'title' => wfMsg( 'tooltip-preview' ), |
| 575 | + ); |
| 576 | + if ( $is_disabled ) { |
| 577 | + $temp['disabled'] = ''; |
| 578 | + } |
| 579 | + return self::buttonHTML( $temp ); |
| 580 | + } |
| 581 | + |
| 582 | + static function showChangesButtonHTML( $is_disabled, $label = null, $attr = array() ) { |
| 583 | + global $sfgTabIndex; |
| 584 | + |
| 585 | + $sfgTabIndex++; |
| 586 | + if ( $label == null ) |
| 587 | + $label = wfMsg( 'showdiff' ); |
| 588 | + $temp = $attr + array( |
| 589 | + 'id' => 'wpDiff', |
| 590 | + 'name' => 'wpDiff', |
| 591 | + 'type' => 'submit', |
| 592 | + 'tabindex' => $sfgTabIndex, |
| 593 | + 'value' => $label, |
| 594 | + 'accesskey' => wfMsg( 'accesskey-diff' ), |
| 595 | + 'title' => wfMsg( 'tooltip-diff' ), |
| 596 | + ); |
| 597 | + if ( $is_disabled ) { |
| 598 | + $temp['disabled'] = ''; |
| 599 | + } |
| 600 | + return self::buttonHTML( $temp ); |
| 601 | + } |
| 602 | + |
| 603 | + static function cancelLinkHTML( $is_disabled, $label = null, $attr = array() ) { |
| 604 | + global $wgUser, $wgTitle; |
| 605 | + |
| 606 | + $sk = $wgUser->getSkin(); |
| 607 | + if ( $label == null ) |
| 608 | + $label = wfMsgExt( 'cancel', array( 'parseinline' ) ); |
| 609 | + if ( $wgTitle == null ) |
| 610 | + $cancel = ''; |
| 611 | + // if we're on the special 'FormEdit' page, just send the user |
| 612 | + // back to the previous page they were on |
| 613 | + elseif ( $wgTitle->getText() == 'FormEdit' |
| 614 | + && $wgTitle->getNamespace() == NS_SPECIAL ) { |
| 615 | + $cancel = '<a href="javascript:history.go(-1);">' . $label . '</a>'; |
| 616 | + } else |
| 617 | + $cancel = $sk->makeKnownLink( $wgTitle->getPrefixedText(), $label ); |
| 618 | + $text = " <span class='editHelp'>$cancel</span>\n"; |
| 619 | + return $text; |
| 620 | + } |
| 621 | + |
| 622 | + static function runQueryButtonHTML( $is_disabled = false, $label = null, $attr = array() ) { |
| 623 | + // is_disabled is currently ignored |
| 624 | + global $sfgTabIndex; |
| 625 | + |
| 626 | + $sfgTabIndex++; |
| 627 | + if ( $label == null ) |
| 628 | + $label = wfMsg( 'runquery' ); |
| 629 | + return self::buttonHTML( $attr + array( |
| 630 | + 'id' => 'wpRunQuery', |
| 631 | + 'name' => 'wpRunQuery', |
| 632 | + 'type' => 'submit', |
| 633 | + 'tabindex' => $sfgTabIndex, |
| 634 | + 'value' => $label, |
| 635 | + 'title' => $label, |
| 636 | + ) ); |
| 637 | + } |
| 638 | + |
| 639 | + // Much of this function is based on MediaWiki's EditPage::showEditForm() |
| 640 | + static function formBottom( $is_disabled ) { |
| 641 | + global $wgUser; |
| 642 | + |
| 643 | + $summary_text = SFFormUtils::summaryInputHTML( $is_disabled ); |
| 644 | + $text = <<<END |
| 645 | + <br /><br /> |
| 646 | + <div class='editOptions'> |
| 647 | +$summary_text <br /> |
| 648 | + |
| 649 | +END; |
| 650 | + if ( $wgUser->isAllowed( 'minoredit' ) ) { |
| 651 | + $text .= SFFormUtils::minorEditInputHTML( $is_disabled ); |
| 652 | + } |
| 653 | + |
| 654 | + if ( $wgUser->isLoggedIn() ) { |
| 655 | + $text .= SFFormUtils::watchInputHTML( $is_disabled ); |
| 656 | + } |
| 657 | + |
| 658 | + $text .= <<<END |
| 659 | + <br /> |
| 660 | + <div class='editButtons'> |
| 661 | + |
| 662 | +END; |
| 663 | + $text .= SFFormUtils::saveButtonHTML( $is_disabled ); |
| 664 | + $text .= SFFormUtils::showPreviewButtonHTML( $is_disabled ); |
| 665 | + $text .= SFFormUtils::showChangesButtonHTML( $is_disabled ); |
| 666 | + $text .= SFFormUtils::cancelLinkHTML( $is_disabled ); |
| 667 | + $text .= <<<END |
| 668 | + </div><!-- editButtons --> |
| 669 | + </div><!-- editOptions --> |
| 670 | + |
| 671 | +END; |
| 672 | + return $text; |
| 673 | + } |
| 674 | + |
| 675 | + // based on MediaWiki's EditPage::getPreloadedText() |
| 676 | + static function getPreloadedText( $preload ) { |
| 677 | + if ( $preload === '' ) { |
| 678 | + return ''; |
| 679 | + } else { |
| 680 | + $preloadTitle = Title::newFromText( $preload ); |
| 681 | + if ( isset( $preloadTitle ) && $preloadTitle->userCanRead() ) { |
| 682 | + $rev = Revision::newFromTitle( $preloadTitle ); |
| 683 | + if ( is_object( $rev ) ) { |
| 684 | + $text = $rev->getText(); |
| 685 | + // Remove <noinclude> sections and <includeonly> tags from text |
| 686 | + $text = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $text ); |
| 687 | + $text = strtr( $text, array( '<includeonly>' => '', '</includeonly>' => '' ) ); |
| 688 | + return $text; |
| 689 | + } |
| 690 | + } |
| 691 | + return ''; |
| 692 | + } |
| 693 | + } |
| 694 | + |
| 695 | + /** |
| 696 | + * Used by 'RunQuery' page |
| 697 | + */ |
| 698 | + static function queryFormBottom() { |
| 699 | + return self::runQueryButtonHTML( false ); |
| 700 | + } |
| 701 | + |
| 702 | + static function getMonthNames() { |
| 703 | + return array( |
| 704 | + wfMsgForContent( 'january' ), |
| 705 | + wfMsgForContent( 'february' ), |
| 706 | + wfMsgForContent( 'march' ), |
| 707 | + wfMsgForContent( 'april' ), |
| 708 | + wfMsgForContent( 'may' ), |
| 709 | + wfMsgForContent( 'june' ), |
| 710 | + wfMsgForContent( 'july' ), |
| 711 | + wfMsgForContent( 'august' ), |
| 712 | + wfMsgForContent( 'september' ), |
| 713 | + wfMsgForContent( 'october' ), |
| 714 | + wfMsgForContent( 'november' ), |
| 715 | + wfMsgForContent( 'december' ) |
| 716 | + ); |
| 717 | + } |
| 718 | + |
| 719 | + static function getShowFCKEditor() { |
| 720 | + global $wgUser, $wgDefaultUserOptions; |
| 721 | + |
| 722 | + $showFCKEditor = 0; |
| 723 | + if ( !$wgUser->getOption( 'riched_start_disabled', $wgDefaultUserOptions['riched_start_disabled'] ) ) { |
| 724 | + $showFCKEditor += RTE_VISIBLE; |
| 725 | + } |
| 726 | + if ( $wgUser->getOption( 'riched_use_popup', $wgDefaultUserOptions['riched_use_popup'] ) ) { |
| 727 | + $showFCKEditor += RTE_POPUP; |
| 728 | + } |
| 729 | + if ( $wgUser->getOption( 'riched_use_toggle', $wgDefaultUserOptions['riched_use_toggle'] ) ) { |
| 730 | + $showFCKEditor += RTE_TOGGLE_LINK; |
| 731 | + } |
| 732 | + |
| 733 | + if ( ( !empty( $_SESSION['showMyFCKeditor'] ) ) && ( $wgUser->getOption( 'riched_toggle_remember_state' ) ) ) |
| 734 | + { |
| 735 | + // clear RTE_VISIBLE flag |
| 736 | + $showFCKEditor &= ~RTE_VISIBLE ; |
| 737 | + // get flag from session |
| 738 | + $showFCKEditor |= $_SESSION['showMyFCKeditor'] ; |
| 739 | + } |
| 740 | + return $showFCKEditor; |
| 741 | + } |
| 742 | + |
| 743 | + static function prepareTextForFCK( $text ) { |
| 744 | + global $wgTitle; |
| 745 | + |
| 746 | + $options = new FCKeditorParserOptions(); |
| 747 | + $options->setTidy( true ); |
| 748 | + $parser = new FCKeditorParser(); |
| 749 | + $parser->setOutputType( OT_HTML ); |
| 750 | + $text = $parser->parse( $text, $wgTitle, $options )->getText(); |
| 751 | + return $text; |
| 752 | + } |
| 753 | + |
| 754 | + static function mainFCKJavascript( $showFCKEditor ) { |
| 755 | + global $wgUser, $wgScriptPath, $wgFCKEditorExtDir, $wgFCKEditorDir, $wgFCKEditorToolbarSet, $wgFCKEditorHeight; |
| 756 | + |
| 757 | + $newWinMsg = wfMsg( 'rich_editor_new_window' ); |
| 758 | + $javascript_text = ' |
| 759 | +var showFCKEditor = ' . $showFCKEditor . '; |
| 760 | +var popup = false; //pointer to popup document |
| 761 | +var firstLoad = true; |
| 762 | +var editorMsgOn = "' . wfMsg( 'textrichditor' ) . '"; |
| 763 | +var editorMsgOff = "' . wfMsg( 'tog-riched_disable' ) . '"; |
| 764 | +var editorLink = "' . ( ( $showFCKEditor & RTE_VISIBLE ) ? wfMsg( 'tog-riched_disable' ): wfMsg( 'textrichditor' ) ) . '"; |
| 765 | +var saveSetting = ' . ( $wgUser->getOption( 'riched_toggle_remember_state' ) ? 1 : 0 ) . '; |
| 766 | +var RTE_VISIBLE = ' . RTE_VISIBLE . '; |
| 767 | +var RTE_TOGGLE_LINK = ' . RTE_TOGGLE_LINK . '; |
| 768 | +var RTE_POPUP = ' . RTE_POPUP . '; |
| 769 | +'; |
| 770 | + |
| 771 | + $javascript_text .= <<<END |
| 772 | +var oFCKeditor = new FCKeditor( "free_text" ); |
| 773 | + |
| 774 | +//Set config |
| 775 | +oFCKeditor.BasePath = '$wgScriptPath/$wgFCKEditorDir/'; |
| 776 | +oFCKeditor.Config["CustomConfigurationsPath"] = "$wgScriptPath/$wgFCKEditorExtDir/fckeditor_config.js" ; |
| 777 | +oFCKeditor.Config["EditorAreaCSS"] = "$wgScriptPath/$wgFCKEditorExtDir/css/fckeditor.css" ; |
| 778 | +oFCKeditor.ToolbarSet = "$wgFCKEditorToolbarSet" ; |
| 779 | +oFCKeditor.ready = true; |
| 780 | + |
| 781 | +//IE hack to call func from popup |
| 782 | +function FCK_sajax(func_name, args, target) { |
| 783 | + sajax_request_type = 'POST' ; |
| 784 | + sajax_do_call(func_name, args, function (x) { |
| 785 | + // I know this is function, not object |
| 786 | + target(x); |
| 787 | + } |
| 788 | + ); |
| 789 | +} |
| 790 | + |
| 791 | +function onLoadFCKeditor() |
| 792 | +{ |
| 793 | + if (!(showFCKEditor & RTE_VISIBLE)) |
| 794 | + showFCKEditor += RTE_VISIBLE; |
| 795 | + firstLoad = false; |
| 796 | + realTextarea = document.getElementById('free_text'); |
| 797 | + if ( realTextarea ) |
| 798 | + { |
| 799 | + // Create the editor instance and replace the textarea. |
| 800 | + oFCKeditor.Height = 300; |
| 801 | + oFCKeditor.ReplaceTextarea() ; |
| 802 | + |
| 803 | + FCKeditorInsertTags = function (tagOpen, tagClose, sampleText, oDoc) |
| 804 | + { |
| 805 | + var txtarea; |
| 806 | + |
| 807 | + if ( !(typeof(oDoc.FCK) == "undefined") && !(typeof(oDoc.FCK.EditingArea) == "undefined") ) |
| 808 | + { |
| 809 | + txtarea = oDoc.FCK.EditingArea.Textarea ; |
| 810 | + } |
| 811 | + else if (oDoc.editform) |
| 812 | + { |
| 813 | + // if we have FCK enabled, behave differently... |
| 814 | + if ( showFCKEditor & RTE_VISIBLE ) |
| 815 | + { |
| 816 | + SRCiframe = oDoc.getElementById ('free_text___Frame') ; |
| 817 | + if ( SRCiframe ) |
| 818 | + { |
| 819 | + if (window.frames[SRCiframe]) |
| 820 | + SRCdoc = window.frames[SRCiframe].oDoc ; |
| 821 | + else |
| 822 | + SRCdoc = SRCiframe.contentDocument ; |
| 823 | + |
| 824 | + var SRCarea = SRCdoc.getElementById ('xEditingArea').firstChild ; |
| 825 | + |
| 826 | + if (SRCarea) |
| 827 | + txtarea = SRCarea ; |
| 828 | + else |
| 829 | + return false ; |
| 830 | + |
| 831 | + } |
| 832 | + else |
| 833 | + { |
| 834 | + return false ; |
| 835 | + } |
| 836 | + } |
| 837 | + else |
| 838 | + { |
| 839 | + txtarea = oDoc.editform.free_text ; |
| 840 | + } |
| 841 | + } |
| 842 | + else |
| 843 | + { |
| 844 | + // some alternate form? take the first one we can find |
| 845 | + var areas = oDoc.getElementsByTagName( 'textarea' ) ; |
| 846 | + txtarea = areas[0] ; |
| 847 | + } |
| 848 | + |
| 849 | + var selText, isSample = false ; |
| 850 | + |
| 851 | + if ( oDoc.selection && oDoc.selection.createRange ) |
| 852 | + { // IE/Opera |
| 853 | + |
| 854 | + //save window scroll position |
| 855 | + if ( oDoc.documentElement && oDoc.documentElement.scrollTop ) |
| 856 | + var winScroll = oDoc.documentElement.scrollTop ; |
| 857 | + else if ( oDoc.body ) |
| 858 | + var winScroll = oDoc.body.scrollTop ; |
| 859 | + |
| 860 | + //get current selection |
| 861 | + txtarea.focus() ; |
| 862 | + var range = oDoc.selection.createRange() ; |
| 863 | + selText = range.text ; |
| 864 | + //insert tags |
| 865 | + checkSelected(); |
| 866 | + range.text = tagOpen + selText + tagClose ; |
| 867 | + //mark sample text as selected |
| 868 | + if ( isSample && range.moveStart ) |
| 869 | + { |
| 870 | + if (window.opera) |
| 871 | + tagClose = tagClose.replace(/\\n/g,'') ; //check it out one more time |
| 872 | + range.moveStart('character', - tagClose.length - selText.length) ; |
| 873 | + range.moveEnd('character', - tagClose.length) ; |
| 874 | + } |
| 875 | + range.select(); |
| 876 | + //restore window scroll position |
| 877 | + if ( oDoc.documentElement && oDoc.documentElement.scrollTop ) |
| 878 | + oDoc.documentElement.scrollTop = winScroll ; |
| 879 | + else if ( oDoc.body ) |
| 880 | + oDoc.body.scrollTop = winScroll ; |
| 881 | + |
| 882 | + } |
| 883 | + else if ( txtarea.selectionStart || txtarea.selectionStart == '0' ) |
| 884 | + { // Mozilla |
| 885 | + |
| 886 | + //save textarea scroll position |
| 887 | + var textScroll = txtarea.scrollTop ; |
| 888 | + //get current selection |
| 889 | + txtarea.focus() ; |
| 890 | + var startPos = txtarea.selectionStart ; |
| 891 | + var endPos = txtarea.selectionEnd ; |
| 892 | + selText = txtarea.value.substring( startPos, endPos ) ; |
| 893 | + |
| 894 | + //insert tags |
| 895 | + if (!selText) |
| 896 | + { |
| 897 | + selText = sampleText ; |
| 898 | + isSample = true ; |
| 899 | + } |
| 900 | + else if (selText.charAt(selText.length - 1) == ' ') |
| 901 | + { //exclude ending space char |
| 902 | + selText = selText.substring(0, selText.length - 1) ; |
| 903 | + tagClose += ' ' ; |
| 904 | + } |
| 905 | + txtarea.value = txtarea.value.substring(0, startPos) + tagOpen + selText + tagClose + |
| 906 | + txtarea.value.substring(endPos, txtarea.value.length) ; |
| 907 | + //set new selection |
| 908 | + if (isSample) |
| 909 | + { |
| 910 | + txtarea.selectionStart = startPos + tagOpen.length ; |
| 911 | + txtarea.selectionEnd = startPos + tagOpen.length + selText.length ; |
| 912 | + } |
| 913 | + else |
| 914 | + { |
| 915 | + txtarea.selectionStart = startPos + tagOpen.length + selText.length + tagClose.length ; |
| 916 | + txtarea.selectionEnd = txtarea.selectionStart; |
| 917 | + } |
| 918 | + //restore textarea scroll position |
| 919 | + txtarea.scrollTop = textScroll; |
| 920 | + } |
| 921 | + } |
| 922 | + } |
| 923 | +} |
| 924 | +function checkSelected() |
| 925 | +{ |
| 926 | + if (!selText) { |
| 927 | + selText = sampleText; |
| 928 | + isSample = true; |
| 929 | + } else if (selText.charAt(selText.length - 1) == ' ') { //exclude ending space char |
| 930 | + selText = selText.substring(0, selText.length - 1); |
| 931 | + tagClose += ' ' |
| 932 | + } |
| 933 | +} |
| 934 | +function initEditor() |
| 935 | +{ |
| 936 | + var toolbar = document.getElementById('free_text'); |
| 937 | + //show popup or toogle link |
| 938 | + if (showFCKEditor & (RTE_POPUP|RTE_TOGGLE_LINK)){ |
| 939 | + var fckTools = document.createElement('div'); |
| 940 | + fckTools.setAttribute('id', 'fckTools'); |
| 941 | + |
| 942 | + var SRCtextarea = document.getElementById( "free_text" ) ; |
| 943 | + if (showFCKEditor & RTE_VISIBLE) SRCtextarea.style.display = "none"; |
| 944 | + } |
| 945 | + |
| 946 | + if (showFCKEditor & RTE_TOGGLE_LINK) |
| 947 | + { |
| 948 | + fckTools.innerHTML='[<a class="fckToogle" id="toggle_free_text" href="javascript:void(0)" onclick="ToggleFCKEditor(\'toggle\',\'free_text\')">'+ editorLink +'</a>] '; |
| 949 | + } |
| 950 | + if (showFCKEditor & RTE_POPUP) |
| 951 | + { |
| 952 | + var style = (showFCKEditor & RTE_VISIBLE) ? 'style="display:none"' : ""; |
| 953 | + fckTools.innerHTML+='<span ' + style + ' id="popup_free_text">[<a class="fckPopup" href="javascript:void(0)" onclick="ToggleFCKEditor(\'popup\',\'free_text\')">{$newWinMsg}</a>]</span>'; |
| 954 | + } |
| 955 | + |
| 956 | + if (showFCKEditor & (RTE_POPUP|RTE_TOGGLE_LINK)){ |
| 957 | + //add new toolbar before wiki toolbar |
| 958 | + toolbar.parentNode.insertBefore( fckTools, toolbar ); |
| 959 | + } |
| 960 | + |
| 961 | + if (showFCKEditor & RTE_VISIBLE) |
| 962 | + { |
| 963 | + if ( toolbar ) //insert wiki buttons |
| 964 | + { |
| 965 | + mwSetupToolbar = function() { return false ; } ; |
| 966 | + |
| 967 | + for (var i = 0; i < mwEditButtons.length; i++) { |
| 968 | + mwInsertEditButton(toolbar, mwEditButtons[i]); |
| 969 | + } |
| 970 | + for (var i = 0; i < mwCustomEditButtons.length; i++) { |
| 971 | + mwInsertEditButton(toolbar, mwCustomEditButtons[i]); |
| 972 | + } |
| 973 | + } |
| 974 | + onLoadFCKeditor(); |
| 975 | + } |
| 976 | + return true; |
| 977 | +} |
| 978 | +addOnloadHook( initEditor ); |
| 979 | + |
| 980 | +END; |
| 981 | + return $javascript_text; |
| 982 | + } |
| 983 | + |
| 984 | + static function FCKToggleJavascript() { |
| 985 | + // add toggle link and handler |
| 986 | + $javascript_text = <<<END |
| 987 | + |
| 988 | +function ToggleFCKEditor(mode, objId) |
| 989 | +{ |
| 990 | + var SRCtextarea = document.getElementById( objId ) ; |
| 991 | + if(mode == 'popup'){ |
| 992 | + if (( showFCKEditor & RTE_VISIBLE) && ( FCKeditorAPI )) //if FCKeditor is up-to-date |
| 993 | + { |
| 994 | + var oEditorIns = FCKeditorAPI.GetInstance( objId ); |
| 995 | + var text = oEditorIns.GetData( oEditorIns.Config.FormatSource ); |
| 996 | + SRCtextarea.value = text; //copy text to textarea |
| 997 | + } |
| 998 | + FCKeditor_OpenPopup('oFCKeditor',objId); |
| 999 | + return true; |
| 1000 | + } |
| 1001 | + |
| 1002 | + var oToggleLink = document.getElementById('toggle_'+ objId ); |
| 1003 | + var oPopupLink = document.getElementById('popup_'+ objId ); |
| 1004 | + |
| 1005 | + if ( firstLoad ) |
| 1006 | + { |
| 1007 | + // firstLoad = true => FCKeditor start invisible |
| 1008 | + // "innerHTML" fails for IE - use "innerText" instead |
| 1009 | + if (oToggleLink) { |
| 1010 | + if (oToggleLink.innerText) |
| 1011 | + oToggleLink.innerText = "Loading..."; |
| 1012 | + else |
| 1013 | + oToggleLink.innerHTML = "Loading..."; |
| 1014 | + } |
| 1015 | + sajax_request_type = 'POST' ; |
| 1016 | + oFCKeditor.ready = false; |
| 1017 | + sajax_do_call('wfSajaxWikiToHTML', [SRCtextarea.value], function ( result ){ |
| 1018 | + if ( firstLoad ) //still |
| 1019 | + { |
| 1020 | + SRCtextarea.value = result.responseText; //insert parsed text |
| 1021 | + onLoadFCKeditor(); |
| 1022 | + // "innerHTML" fails for IE - use "innerText" instead |
| 1023 | + if (oToggleLink) { |
| 1024 | + if (oToggleLink.innerText) |
| 1025 | + oToggleLink.innerText = editorMsgOff; |
| 1026 | + else |
| 1027 | + oToggleLink.innerHTML = editorMsgOff; |
| 1028 | + } |
| 1029 | + oFCKeditor.ready = true; |
| 1030 | + } |
| 1031 | + }); |
| 1032 | + return true; |
| 1033 | + } |
| 1034 | + |
| 1035 | + if (!oFCKeditor.ready) return false; //sajax_do_call in action |
| 1036 | + if (!FCKeditorAPI) return false; //not loaded yet |
| 1037 | + var oEditorIns = FCKeditorAPI.GetInstance( objId ); |
| 1038 | + var oEditorIframe = document.getElementById( objId+'___Frame' ); |
| 1039 | + var FCKtoolbar = document.getElementById('toolbar'); |
| 1040 | + var bIsWysiwyg = ( oEditorIns.EditMode == FCK_EDITMODE_WYSIWYG ); |
| 1041 | + |
| 1042 | + //FCKeditor visible -> hidden |
| 1043 | + if ( showFCKEditor & RTE_VISIBLE) |
| 1044 | + { |
| 1045 | + var text = oEditorIns.GetData( oEditorIns.Config.FormatSource ); |
| 1046 | + SRCtextarea.value = text; |
| 1047 | + if ( bIsWysiwyg ) oEditorIns.SwitchEditMode(); //switch to plain |
| 1048 | + var text = oEditorIns.GetData( oEditorIns.Config.FormatSource ); |
| 1049 | + //copy from FCKeditor to textarea |
| 1050 | + SRCtextarea.value = text; |
| 1051 | + if (saveSetting) |
| 1052 | + { |
| 1053 | + sajax_request_type = 'GET' ; |
| 1054 | + sajax_do_call( 'wfSajaxToggleFCKeditor', ['hide'], function(){} ) ; //remember closing in session |
| 1055 | + } |
| 1056 | + if (oToggleLink) { |
| 1057 | + if (oToggleLink.innerText) |
| 1058 | + oToggleLink.innerText = editorMsgOn; |
| 1059 | + else |
| 1060 | + oToggleLink.innerHTML = editorMsgOn; |
| 1061 | + } |
| 1062 | + if (oPopupLink) oPopupLink.style.display = ''; |
| 1063 | + showFCKEditor -= RTE_VISIBLE; |
| 1064 | + oEditorIframe.style.display = 'none'; |
| 1065 | + //FCKtoolbar.style.display = ''; |
| 1066 | + SRCtextarea.style.display = ''; |
| 1067 | + } |
| 1068 | + //FCKeditor hidden -> visible |
| 1069 | + else |
| 1070 | + { |
| 1071 | + if ( bIsWysiwyg ) oEditorIns.SwitchEditMode(); //switch to plain |
| 1072 | + SRCtextarea.style.display = 'none'; |
| 1073 | + //copy from textarea to FCKeditor |
| 1074 | + oEditorIns.EditingArea.Textarea.value = SRCtextarea.value |
| 1075 | + //FCKtoolbar.style.display = 'none'; |
| 1076 | + oEditorIframe.style.display = ''; |
| 1077 | + if ( !bIsWysiwyg ) oEditorIns.SwitchEditMode(); //switch to WYSIWYG |
| 1078 | + showFCKEditor += RTE_VISIBLE; |
| 1079 | + if (oToggleLink) { |
| 1080 | + if (oToggleLink.innerText) |
| 1081 | + oToggleLink.innerText = editorMsgOff; |
| 1082 | + else |
| 1083 | + oToggleLink.innerHTML = editorMsgOff; |
| 1084 | + } |
| 1085 | + if (oPopupLink) oPopupLink.style.display = 'none'; |
| 1086 | + } |
| 1087 | + return true; |
| 1088 | +} |
| 1089 | + |
| 1090 | +END; |
| 1091 | + return $javascript_text; |
| 1092 | + } |
| 1093 | + |
| 1094 | + static function FCKPopupJavascript() { |
| 1095 | + global $wgFCKEditorExtDir; |
| 1096 | + $javascript_text = <<<END |
| 1097 | + |
| 1098 | +function FCKeditor_OpenPopup(jsID, textareaID) |
| 1099 | +{ |
| 1100 | + popupUrl = '${wgFCKEditorExtDir}/FCKeditor.popup.html'; |
| 1101 | + popupUrl = popupUrl + '?var='+ jsID + '&el=' + textareaID; |
| 1102 | + window.open(popupUrl, null, 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=1,dependent=yes'); |
| 1103 | + return 0; |
| 1104 | +} |
| 1105 | + |
| 1106 | +END; |
| 1107 | + return $javascript_text; |
| 1108 | + } |
| 1109 | +} |
Property changes on: trunk/extensions/SemanticForms/includes/SF_FormUtils.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 1110 | + native |
Index: trunk/extensions/SemanticForms/includes/SF_FormInputs.php |
— | — | @@ -0,0 +1,895 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Helper functions to display the various inputs of a user-generated form |
| 5 | + * |
| 6 | + * @author Yaron Koren |
| 7 | + * @author Jeffrey Stuckman |
| 8 | + * @author Matt Williamson |
| 9 | + * @author Patrick Nagel |
| 10 | + */ |
| 11 | + |
| 12 | +class SFFormInputs { |
| 13 | + |
| 14 | + /** |
| 15 | + * Create a comma-delimited string of values that match the specified |
| 16 | + * source name and type, for use by Javascript autocompletion. |
| 17 | + */ |
| 18 | + static function createAutocompleteValuesString( $source_name, $source_type ) { |
| 19 | + $names_array = array(); |
| 20 | + // the query depends on whether this is a property, category, concept |
| 21 | + // or namespace |
| 22 | + if ( $source_type == 'property' || $source_type == 'attribute' || $source_type == 'relation' ) { |
| 23 | + $names_array = SFUtils::getAllValuesForProperty( $source_name ); |
| 24 | + } elseif ( $source_type == 'category' ) { |
| 25 | + $names_array = SFUtils::getAllPagesForCategory( $source_name, 10 ); |
| 26 | + } elseif ( $source_type == 'concept' ) { |
| 27 | + $names_array = SFUtils::getAllPagesForConcept( $source_name ); |
| 28 | + } else { // i.e., $source_type == 'namespace' |
| 29 | + // switch back to blank for main namespace |
| 30 | + if ( $source_name == "Main" ) |
| 31 | + $source_name = ""; |
| 32 | + $names_array = SFUtils::getAllPagesForNamespace( $source_name ); |
| 33 | + } |
| 34 | + // escape quotes, to avoid Javascript errors |
| 35 | + $names_array = array_map( 'addslashes', $names_array ); |
| 36 | + $autocomplete_string = "[['" . implode( "'], ['", $names_array ) . "']]"; |
| 37 | + // replace any newlines in the string, just to avoid breaking the Javascript |
| 38 | + $autocomplete_string = str_replace( "\n", ' ', $autocomplete_string ); |
| 39 | + $autocomplete_string = str_replace( "\r", ' ', $autocomplete_string ); |
| 40 | + return $autocomplete_string; |
| 41 | + } |
| 42 | + |
| 43 | + static function uploadLinkHTML( $input_id, $delimiter = null, $default_filename = null ) { |
| 44 | + $upload_window_page = SpecialPage::getPage( 'UploadWindow' ); |
| 45 | + $query_string = "sfInputID=$input_id"; |
| 46 | + if ( $delimiter != null ) |
| 47 | + $query_string .= "&sfDelimiter=$delimiter"; |
| 48 | + if ( $default_filename != null ) |
| 49 | + $query_string .= "&wpDestFile=$default_filename"; |
| 50 | + $upload_window_url = $upload_window_page->getTitle()->getFullURL( $query_string ); |
| 51 | + $upload_label = wfMsg( 'upload' ); |
| 52 | + // window needs to be bigger for MediaWiki version 1.16+ |
| 53 | + if ( class_exists( 'HTMLForm' ) ) |
| 54 | + $style = "width:650 height:500"; |
| 55 | + else |
| 56 | + $style = ''; |
| 57 | + $text = " <a href=\"$upload_window_url\" title=\"$upload_label\" rel=\"iframe\" rev=\"$style\">$upload_label</a>"; |
| 58 | + return $text; |
| 59 | + } |
| 60 | + |
| 61 | + static function textEntryHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 62 | + // if it's an autocomplete, call the with-autocomplete function instead |
| 63 | + if ( array_key_exists( 'autocompletion source', $other_args ) ) { |
| 64 | + return self::textInputWithAutocompleteHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
| 65 | + } |
| 66 | + |
| 67 | + // if there are possible values specified, call the dropdown function |
| 68 | + if ( array_key_exists( 'possible_values', $other_args ) && $other_args['possible_values'] != null ) |
| 69 | + return SFFormInputs::dropdownHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
| 70 | + |
| 71 | + global $sfgTabIndex, $sfgFieldNum, $sfgJSValidationCalls; |
| 72 | + |
| 73 | + $className = ( $is_mandatory ) ? "createboxInput mandatoryField" : "createboxInput"; |
| 74 | + if ( array_key_exists( 'class', $other_args ) ) |
| 75 | + $className .= " " . $other_args['class']; |
| 76 | + $input_id = "input_$sfgFieldNum"; |
| 77 | + $info_id = "info_$sfgFieldNum"; |
| 78 | + // set size based on pre-set size, or field type - if field type is set, |
| 79 | + // possibly add validation too |
| 80 | + if ( array_key_exists( 'size', $other_args ) ) { |
| 81 | + $size = $other_args['size']; |
| 82 | + } elseif ( array_key_exists( 'field_type', $other_args ) ) { |
| 83 | + $validation_type_str = ""; |
| 84 | + if ( $other_args['field_type'] == 'integer' ) { |
| 85 | + $size = 10; |
| 86 | + $validation_type_str = 'integer'; |
| 87 | + } elseif ( $other_args['field_type'] == 'number' ) { |
| 88 | + $size = 10; |
| 89 | + $validation_type_str = 'number'; |
| 90 | + } elseif ( $other_args['field_type'] == 'URL' ) { |
| 91 | + $size = 100; |
| 92 | + $validation_type_str = 'URL'; |
| 93 | + } elseif ( $other_args['field_type'] == 'email' ) { |
| 94 | + $size = 45; |
| 95 | + $validation_type_str = 'email'; |
| 96 | + } else { |
| 97 | + $size = 35; |
| 98 | + } |
| 99 | + if ( $validation_type_str != '' ) { |
| 100 | + if ( array_key_exists( 'part_of_multiple', $other_args ) ) { |
| 101 | + $sfgJSValidationCalls[] = "validate_type_of_multiple_fields($sfgFieldNum, '$validation_type_str')"; |
| 102 | + } else { |
| 103 | + $sfgJSValidationCalls[] = "validate_field_type('$input_id', '$validation_type_str', '$info_id')"; |
| 104 | + } |
| 105 | + } |
| 106 | + } else { |
| 107 | + $size = 35; |
| 108 | + } |
| 109 | + if ( ! is_null( $cur_value ) && ! is_array( $cur_value ) ) |
| 110 | + $cur_value = htmlspecialchars( $cur_value ); |
| 111 | + |
| 112 | + $text = <<<END |
| 113 | + <input id="$input_id" tabindex="$sfgTabIndex" class="$className" name="$input_name" type="text" value="$cur_value" size="$size" |
| 114 | +END; |
| 115 | + if ( $is_disabled ) |
| 116 | + $text .= " disabled"; |
| 117 | + if ( array_key_exists( 'maxlength', $other_args ) ) |
| 118 | + $text .= ' maxlength="' . $other_args['maxlength'] . '"'; |
| 119 | + $text .= <<<END |
| 120 | +/> |
| 121 | + <span id="$info_id" class="errorMessage"></span> |
| 122 | + |
| 123 | +END; |
| 124 | + if ( array_key_exists( 'is_uploadable', $other_args ) && $other_args['is_uploadable'] == true ) { |
| 125 | + if ( array_key_exists( 'is_list', $other_args ) && $other_args['is_list'] == true ) { |
| 126 | + if ( array_key_exists( 'delimiter', $other_args ) ) { |
| 127 | + $delimiter = $other_args['delimiter']; |
| 128 | + } else { |
| 129 | + $delimiter = ","; |
| 130 | + } |
| 131 | + } else { |
| 132 | + $delimiter = null; |
| 133 | + } |
| 134 | + if ( array_key_exists( 'default filename', $other_args ) ) { |
| 135 | + $default_filename = $other_args['default filename']; |
| 136 | + } else { |
| 137 | + $default_filename = ""; |
| 138 | + } |
| 139 | + $text .= SFFormInputs::uploadLinkHTML( $input_id, $delimiter, $default_filename ); |
| 140 | + } |
| 141 | + return array( $text, null ); |
| 142 | + } |
| 143 | + |
| 144 | + static function dropdownHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 145 | + global $sfgTabIndex, $sfgFieldNum; |
| 146 | + |
| 147 | + $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
| 148 | + if ( array_key_exists( 'class', $other_args ) ) |
| 149 | + $className .= " " . $other_args['class']; |
| 150 | + $input_id = "input_$sfgFieldNum"; |
| 151 | + $info_id = "info_$sfgFieldNum"; |
| 152 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 153 | + $javascript_text = ''; |
| 154 | + $return_js_text = ''; |
| 155 | + if ( array_key_exists( 'show on select', $other_args ) ) { |
| 156 | + $javascript_text = 'onChange="'; |
| 157 | + foreach ( $other_args['show on select'] as $div_id => $options ) { |
| 158 | + $options_str = implode( "', '", $options ); |
| 159 | + $this_js_text = "showIfSelected('$input_id', ['$options_str'], '$div_id'); "; |
| 160 | + $javascript_text .= $this_js_text; |
| 161 | + $return_js_text .= $this_js_text . "\n"; |
| 162 | + } |
| 163 | + $javascript_text .= '"'; |
| 164 | + } |
| 165 | + $text = <<<END |
| 166 | + <select id="$input_id" tabindex="$sfgTabIndex" name="$input_name" class="$className" $disabled_text $javascript_text> |
| 167 | + |
| 168 | +END; |
| 169 | + // add a blank value at the beginning, unless this is a mandatory field |
| 170 | + // and there's a current value in place (either through a default value |
| 171 | + // or because we're editing an existing page) |
| 172 | + if ( ! $is_mandatory || $cur_value == '' ) { |
| 173 | + $text .= " <option value=\"\"></option>\n"; |
| 174 | + } |
| 175 | + if ( ( $possible_values = $other_args['possible_values'] ) == null ) |
| 176 | + $possible_values = array(); |
| 177 | + foreach ( $possible_values as $possible_value ) { |
| 178 | + $text .= " <option value=\"$possible_value\""; |
| 179 | + if ( $possible_value == $cur_value ) { $text .= " selected=\"selected\""; } |
| 180 | + $text .= ">"; |
| 181 | + if ( array_key_exists( 'value_labels', $other_args ) && is_array( $other_args['value_labels'] ) && array_key_exists( $possible_value, $other_args['value_labels'] ) ) |
| 182 | + $text .= htmlspecialchars( $other_args['value_labels'][$possible_value] ); |
| 183 | + else |
| 184 | + $text .= $possible_value; |
| 185 | + $text .= "</option>\n"; |
| 186 | + } |
| 187 | + $text .= <<<END |
| 188 | + </select> |
| 189 | + <span id="$info_id" class="errorMessage"></span> |
| 190 | + |
| 191 | +END; |
| 192 | + return array( $text, $return_js_text ); |
| 193 | + } |
| 194 | + |
| 195 | + /** |
| 196 | + * Helper function to get an array of values out of what may be either |
| 197 | + * an array or a delimited string |
| 198 | + */ |
| 199 | + static function getValuesArray( $value, $delimiter ) { |
| 200 | + if ( is_array( $value ) ) { |
| 201 | + return $value; |
| 202 | + } else { |
| 203 | + // remove extra spaces |
| 204 | + return array_map( 'trim', explode( $delimiter, $value ) ); |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + static function listboxHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 209 | + global $sfgTabIndex, $sfgFieldNum; |
| 210 | + |
| 211 | + $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
| 212 | + if ( array_key_exists( 'class', $other_args ) ) |
| 213 | + $className .= " " . $other_args['class']; |
| 214 | + $input_id = "input_$sfgFieldNum"; |
| 215 | + $info_id = "info_$sfgFieldNum"; |
| 216 | + $hidden_input_name = $input_name . "[is_list]"; |
| 217 | + $input_name .= "[]"; // needed so that this input will send an array |
| 218 | + if ( array_key_exists( 'size', $other_args ) ) |
| 219 | + $size_text = "size=" . $other_args['size']; |
| 220 | + else |
| 221 | + $size_text = ""; |
| 222 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 223 | + // get list delimiter - default is comma |
| 224 | + if ( array_key_exists( 'delimiter', $other_args ) ) { |
| 225 | + $delimiter = $other_args['delimiter']; |
| 226 | + } else { |
| 227 | + $delimiter = ","; |
| 228 | + } |
| 229 | + $cur_values = self::getValuesArray( $cur_value, $delimiter ); |
| 230 | + |
| 231 | + $javascript_text = ''; |
| 232 | + $return_js_text = ''; |
| 233 | + if ( array_key_exists( 'show on select', $other_args ) ) { |
| 234 | + $javascript_text = 'onChange="'; |
| 235 | + foreach ( $other_args['show on select'] as $div_id => $options ) { |
| 236 | + $options_str = implode( "', '", $options ); |
| 237 | + $this_js_text = "showIfSelected('$input_id', ['$options_str'], '$div_id'); "; |
| 238 | + $javascript_text .= $this_js_text; |
| 239 | + $return_js_text .= $this_js_text . "\n"; |
| 240 | + } |
| 241 | + $javascript_text .= '"'; |
| 242 | + } |
| 243 | + |
| 244 | + $text = <<<END |
| 245 | + <select id="$input_id" tabindex="$sfgTabIndex" name="$input_name" class="$className" multiple $size_text $disabled_text $javascript_text> |
| 246 | + |
| 247 | +END; |
| 248 | + if ( ( $possible_values = $other_args['possible_values'] ) == null ) |
| 249 | + $possible_values = array(); |
| 250 | + foreach ( $possible_values as $possible_value ) { |
| 251 | + $text .= " <option value=\"$possible_value\""; |
| 252 | + if ( in_array( $possible_value, $cur_values ) ) { $text .= " selected"; } |
| 253 | + $text .= ">"; |
| 254 | + if ( array_key_exists( 'value_labels', $other_args ) && is_array( $other_args['value_labels'] ) && array_key_exists( $possible_value, $other_args['value_labels'] ) ) |
| 255 | + $text .= htmlspecialchars( $other_args['value_labels'][$possible_value] ); |
| 256 | + else |
| 257 | + $text .= $possible_value; |
| 258 | + $text .= "</option>\n"; |
| 259 | + } |
| 260 | + $text .= <<<END |
| 261 | + </select> |
| 262 | + <span id="$info_id" class="errorMessage"></span> |
| 263 | + <input type="hidden" name="$hidden_input_name" value="1" /> |
| 264 | + |
| 265 | +END; |
| 266 | + return array( $text, $return_js_text ); |
| 267 | + } |
| 268 | + |
| 269 | + static function checkboxesHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 270 | + global $sfgTabIndex, $sfgFieldNum; |
| 271 | + |
| 272 | + $checkbox_class = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
| 273 | + $span_class = "checkboxSpan"; |
| 274 | + if ( array_key_exists( 'class', $other_args ) ) |
| 275 | + $span_class .= " " . $other_args['class']; |
| 276 | + $input_id = "input_$sfgFieldNum"; |
| 277 | + $info_id = "info_$sfgFieldNum"; |
| 278 | + $hidden_input_name = $input_name . "[is_list]"; |
| 279 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 280 | + // get list delimiter - default is comma |
| 281 | + if ( array_key_exists( 'delimiter', $other_args ) ) { |
| 282 | + $delimiter = $other_args['delimiter']; |
| 283 | + } else { |
| 284 | + $delimiter = ","; |
| 285 | + } |
| 286 | + $cur_values = self::getValuesArray( $cur_value, $delimiter ); |
| 287 | + |
| 288 | + if ( ( $possible_values = $other_args['possible_values'] ) == null ) |
| 289 | + $possible_values = array(); |
| 290 | + $text = ""; |
| 291 | + $return_js_text = ""; |
| 292 | + $enum_input_ids = array(); |
| 293 | + // if it's mandatory, add a span around all the checkboxes, since |
| 294 | + // some browsers don't support formatting of checkboxes |
| 295 | + if ( $is_mandatory ) |
| 296 | + $text .= ' <span class="mandatoryFieldsSpan">' . "\n"; |
| 297 | + foreach ( $possible_values as $key => $possible_value ) { |
| 298 | + // create array $enum_input_ids to associate values with their input IDs, |
| 299 | + // for use in creating the 'show on select' Javascript later |
| 300 | + $enum_input_ids[$possible_value] = $input_id; |
| 301 | + $cur_input_name = $input_name . "[" . $key . "]"; |
| 302 | + $checked_text = ( in_array( $possible_value, $cur_values ) ) ? 'checked="checked"' : ""; |
| 303 | + |
| 304 | + if ( array_key_exists( 'value_labels', $other_args ) && is_array( $other_args['value_labels'] ) && array_key_exists( $possible_value, $other_args['value_labels'] ) ) |
| 305 | + $label = htmlspecialchars( $other_args['value_labels'][$possible_value] ); |
| 306 | + else |
| 307 | + $label = $possible_value; |
| 308 | + $text .= <<<END |
| 309 | + <span class="$span_class"><input type="checkbox" id="$input_id" tabindex="$sfgTabIndex" name="$cur_input_name" value="$possible_value" class="$checkbox_class" $checked_text $disabled_text/> $label</span> |
| 310 | + |
| 311 | +END; |
| 312 | + $sfgTabIndex++; |
| 313 | + $sfgFieldNum++; |
| 314 | + $input_id = "input_$sfgFieldNum"; |
| 315 | + } |
| 316 | + // close span |
| 317 | + if ( $is_mandatory ) |
| 318 | + $text .= " </span>"; |
| 319 | + $text .= <<<END |
| 320 | + <span id="$info_id" class="errorMessage"></span> |
| 321 | + <input type="hidden" name="$hidden_input_name" value="1" /> |
| 322 | + |
| 323 | +END; |
| 324 | + |
| 325 | + $return_js_text = ''; |
| 326 | + if ( array_key_exists( 'show on select', $other_args ) ) { |
| 327 | + foreach ( $other_args['show on select'] as $div_id => $options ) { |
| 328 | + $cur_input_ids = array(); |
| 329 | + foreach ( $options as $option ) { |
| 330 | + if ( array_key_exists( $option, $enum_input_ids ) ) { |
| 331 | + $cur_input_ids[] = $enum_input_ids[$option]; |
| 332 | + } |
| 333 | + } |
| 334 | + $options_str = "['" . implode( "', '", $cur_input_ids ) . "']"; |
| 335 | + $cur_js_text = "showIfChecked($options_str, '$div_id'); "; |
| 336 | + $return_js_text .= $cur_js_text . "\n"; |
| 337 | + foreach ( $possible_values as $key => $possible_value ) { |
| 338 | + $cur_input_id = $enum_input_ids[$possible_value]; |
| 339 | + // we use addClickHandler(), instead of adding the Javascript via |
| 340 | + // onClick="", because MediaWiki's wikibits.js does its own handling |
| 341 | + // of checkboxes, which impacts their behavior in IE |
| 342 | + if ( in_array( $possible_value, $options ) ) { |
| 343 | + $return_js_text .= <<<END |
| 344 | +addClickHandler( |
| 345 | + document.getElementById('$cur_input_id'), |
| 346 | + function() { $cur_js_text } |
| 347 | +); |
| 348 | + |
| 349 | +END; |
| 350 | + } |
| 351 | + } |
| 352 | + } |
| 353 | + } |
| 354 | + |
| 355 | + // do the replacements |
| 356 | + foreach ( $enum_input_ids as $enum_val => $input_id ) { |
| 357 | + $return_js_text = str_replace( "<<$enum_val>>", "'$input_id'", $return_js_text ); |
| 358 | + } |
| 359 | + return array( $text, $return_js_text ); |
| 360 | + } |
| 361 | + |
| 362 | + static function textInputWithAutocompleteHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 363 | + // if 'no autocomplete' was specified, print a regular text entry instead |
| 364 | + if ( array_key_exists( 'no autocomplete', $other_args ) && |
| 365 | + $other_args['no autocomplete'] == true ) { |
| 366 | + unset( $other_args['autocompletion source'] ); |
| 367 | + return SFFormInputs::textEntryHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
| 368 | + } |
| 369 | + // if a set of values was specified, print a dropdown instead |
| 370 | + if ( array_key_exists( 'possible_values', $other_args ) && $other_args['possible_values'] != null ) |
| 371 | + return SFFormInputs::dropdownHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
| 372 | + |
| 373 | + global $sfgTabIndex, $sfgFieldNum; |
| 374 | + |
| 375 | + $className = ( $is_mandatory ) ? "autocompleteInput mandatoryField" : "autocompleteInput createboxInput"; |
| 376 | + if ( array_key_exists( 'class', $other_args ) ) |
| 377 | + $className .= " " . $other_args['class']; |
| 378 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 379 | + if ( array_key_exists( 'autocomplete field type', $other_args ) ) { |
| 380 | + $autocomplete_field_type = $other_args['autocomplete field type']; |
| 381 | + $autocompletion_source = $other_args['autocompletion source']; |
| 382 | + if ( $autocomplete_field_type != 'external_url' ) { |
| 383 | + global $wgContLang; |
| 384 | + $autocompletion_source = $wgContLang->ucfirst( $autocompletion_source ); |
| 385 | + } |
| 386 | + } |
| 387 | + $input_id = "input_" . $sfgFieldNum; |
| 388 | + $info_id = "info_" . $sfgFieldNum; |
| 389 | + $div_name = "div_" . $sfgFieldNum; |
| 390 | + if ( array_key_exists( 'input_type', $other_args ) && $other_args['input_type'] == "textarea" ) { |
| 391 | + $rows = $other_args['rows']; |
| 392 | + $cols = $other_args['cols']; |
| 393 | + if ( array_key_exists( 'maxlength', $other_args ) ) { |
| 394 | + $maxlength = $other_args['maxlength']; |
| 395 | + // is this an unnecessary performance load? Get the substring of the |
| 396 | + // text on every key press or release, regardless of the current length |
| 397 | + // of the text |
| 398 | + $js_call = " onKeyDown=\"this.value = this.value.substring(0, $maxlength);\" onKeyUp=\"this.value = this.value.substring(0, $maxlength);\""; |
| 399 | + } else { |
| 400 | + $js_call = ""; |
| 401 | + } |
| 402 | + $text = <<<END |
| 403 | + <textarea tabindex="$sfgTabIndex" id="$input_id" name="$input_name" rows="$rows" cols="$cols" class="$className" $disabled_text $js_call></textarea> |
| 404 | + |
| 405 | +END; |
| 406 | + } else { |
| 407 | + if ( array_key_exists( 'size', $other_args ) ) |
| 408 | + $size = $other_args['size']; |
| 409 | + else |
| 410 | + $size = "35"; |
| 411 | + |
| 412 | + $text = <<<END |
| 413 | + <input tabindex="$sfgTabIndex" id="$input_id" name="$input_name" type="text" value="" size="$size" class="$className" |
| 414 | +END; |
| 415 | + if ( $is_disabled ) |
| 416 | + $text .= " disabled"; |
| 417 | + if ( array_key_exists( 'maxlength', $other_args ) ) |
| 418 | + $text .= ' maxlength="' . $other_args['maxlength'] . '"'; |
| 419 | + $text .= "/>\n"; |
| 420 | + } |
| 421 | + // is_list and delimiter variables - needed later |
| 422 | + $is_list = ( array_key_exists( 'is_list', $other_args ) && $other_args['is_list'] == true ); |
| 423 | + if ( $is_list ) { |
| 424 | + if ( array_key_exists( 'delimiter', $other_args ) ) { |
| 425 | + $delimiter = $other_args['delimiter']; |
| 426 | + } else { |
| 427 | + $delimiter = ","; |
| 428 | + } |
| 429 | + } else { |
| 430 | + $delimiter = null; |
| 431 | + } |
| 432 | + if ( array_key_exists( 'is_uploadable', $other_args ) && $other_args['is_uploadable'] == true ) { |
| 433 | + if ( array_key_exists( 'default filename', $other_args ) ) { |
| 434 | + $default_filename = $other_args['default filename']; |
| 435 | + } else { |
| 436 | + $default_filename = ""; |
| 437 | + } |
| 438 | + $text .= SFFormInputs::uploadLinkHTML( $input_id, $delimiter, $default_filename ); |
| 439 | + } |
| 440 | + $text .= <<<END |
| 441 | + <span id="$info_id" class="errorMessage"></span> |
| 442 | + <div class="page_name_auto_complete" id="$div_name"></div> |
| 443 | +<script type="text/javascript">/* <![CDATA[ */ |
| 444 | + |
| 445 | +END; |
| 446 | + $options_str_key = str_replace( "'", "\'", $autocompletion_source ); |
| 447 | + if ( $is_list ) { |
| 448 | + $options_str_key .= ",list"; |
| 449 | + if ( $delimiter != "," ) { |
| 450 | + $options_str_key .= "," . $delimiter; |
| 451 | + } |
| 452 | + } |
| 453 | + $javascript_text = "autocompletemappings[$sfgFieldNum] = '$options_str_key';\n"; |
| 454 | + if ( array_key_exists( 'remote autocompletion', $other_args ) && |
| 455 | + $other_args['remote autocompletion'] == true ) { |
| 456 | + $javascript_text .= "autocompletedatatypes['$options_str_key'] = '$autocomplete_field_type';\n"; |
| 457 | + } elseif ( $autocompletion_source != '' ) { |
| 458 | + $autocomplete_string = self::createAutocompleteValuesString( $autocompletion_source, $autocomplete_field_type ); |
| 459 | + $javascript_text .= "autocompletestrings['$options_str_key'] = $autocomplete_string;\n"; |
| 460 | + } |
| 461 | + if ( $cur_value ) { |
| 462 | + // replace various values to not break the Javascript |
| 463 | + $cur_value = str_replace( '"', '\"', $cur_value ); |
| 464 | + $cur_value = str_replace( "\n", '\n', $cur_value ); |
| 465 | + $cur_value = str_replace( "\r", '\r', $cur_value ); |
| 466 | + $text .= "document.getElementById('$input_id').value = \"$cur_value\"\n"; |
| 467 | + } |
| 468 | + $text .= "/* ]]> */</script>\n"; |
| 469 | + return array( $text, $javascript_text ); |
| 470 | + } |
| 471 | + |
| 472 | + static function textAreaHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 473 | + // set size values |
| 474 | + if ( ! array_key_exists( 'rows', $other_args ) ) |
| 475 | + $other_args['rows'] = 5; |
| 476 | + if ( ! array_key_exists( 'cols', $other_args ) ) |
| 477 | + $other_args['cols'] = 80; |
| 478 | + |
| 479 | + // if it's an autocomplete, call the with-autocomplete function instead |
| 480 | + if ( array_key_exists( 'autocompletion source', $other_args ) ) { |
| 481 | + $other_args['input_type'] = "textarea"; |
| 482 | + return SFFormInputs::textInputWithAutocompleteHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ); |
| 483 | + } |
| 484 | + |
| 485 | + global $sfgTabIndex, $sfgFieldNum; |
| 486 | + |
| 487 | + $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
| 488 | + if ( array_key_exists( 'class', $other_args ) ) |
| 489 | + $className .= " " . $other_args['class']; |
| 490 | + $info_id = "info_$sfgFieldNum"; |
| 491 | + // use a special ID for the free text field, for FCK's needs |
| 492 | + $input_id = $input_name == "free_text" ? "free_text" : "input_$sfgFieldNum"; |
| 493 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 494 | + |
| 495 | + $rows = $other_args['rows']; |
| 496 | + $cols = $other_args['cols']; |
| 497 | + if ( array_key_exists( 'maxlength', $other_args ) ) { |
| 498 | + $maxlength = $other_args['maxlength']; |
| 499 | + // is this an unnecessary performance load? Get the substring of the |
| 500 | + // text on every key press or release, regardless of the current length |
| 501 | + // of the text |
| 502 | + $js_call = " onKeyDown=\"this.value = this.value.substring(0, $maxlength);\" onKeyUp=\"this.value = this.value.substring(0, $maxlength);\""; |
| 503 | + } else { |
| 504 | + $js_call = ""; |
| 505 | + } |
| 506 | + |
| 507 | + $cur_value = htmlspecialchars( $cur_value ); |
| 508 | + $text = <<<END |
| 509 | + <textarea tabindex="$sfgTabIndex" id="$input_id" name="$input_name" rows="$rows" cols="$cols" class="$className" $disabled_text $js_call>$cur_value</textarea> |
| 510 | + <span id="$info_id" class="errorMessage"></span> |
| 511 | + |
| 512 | +END; |
| 513 | + return array( $text, null ); |
| 514 | + } |
| 515 | + |
| 516 | + static function monthDropdownHTML( $cur_month, $input_name, $is_disabled ) { |
| 517 | + global $sfgTabIndex, $sfgFieldNum, $wgAmericanDates; |
| 518 | + |
| 519 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 520 | + $text = ' <select tabindex="' . $sfgTabIndex . '" id="input_' . $sfgFieldNum . '_month" name="' . $input_name . "[month]\" $disabled_text>\n"; |
| 521 | + $month_names = SFFormUtils::getMonthNames(); |
| 522 | + foreach ( $month_names as $i => $name ) { |
| 523 | + // pad out month to always be two digits |
| 524 | + $month_value = ( $wgAmericanDates == true ) ? $name : str_pad( $i + 1, 2, "0", STR_PAD_LEFT ); |
| 525 | + $text .= " <option value=\"$month_value\""; |
| 526 | + if ( $name == $cur_month || ( $i + 1 ) == $cur_month ) { $text .= " selected=\"selected\""; } |
| 527 | + $text .= ">$name</option>\n"; |
| 528 | + } |
| 529 | + $text .= " </select>\n"; |
| 530 | + return $text; |
| 531 | + } |
| 532 | + |
| 533 | + static function dateEntryHTML( $date, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 534 | + global $sfgTabIndex, $sfgFieldNum, $sfgJSValidationCalls, $wgAmericanDates; |
| 535 | + |
| 536 | + $input_id = "input_$sfgFieldNum"; |
| 537 | + $info_id = "info_$sfgFieldNum"; |
| 538 | + // add to validation calls |
| 539 | + if ( array_key_exists( 'part_of_multiple', $other_args ) ) { |
| 540 | + $sfgJSValidationCalls[] = "validate_type_of_multiple_fields($sfgFieldNum, 'date')"; |
| 541 | + } else { |
| 542 | + $sfgJSValidationCalls[] = "validate_field_type('$input_id', 'date', '$info_id')"; |
| 543 | + } |
| 544 | + |
| 545 | + if ( $date ) { |
| 546 | + // can show up here either as an array or a string, depending on |
| 547 | + // whether it came from user input or a wiki page |
| 548 | + if ( is_array( $date ) ) { |
| 549 | + $year = $date['year']; |
| 550 | + $month = $date['month']; |
| 551 | + $day = $date['day']; |
| 552 | + } else { |
| 553 | + // handle 'default=now' |
| 554 | + if ( $date == 'now' ) $date = date( 'Y/m/d' ); |
| 555 | + $actual_date = new SMWTimeValue( '_dat' ); |
| 556 | + $actual_date->setUserValue( $date ); |
| 557 | + $year = $actual_date->getYear(); |
| 558 | + // TODO - the code to convert from negative to BC notation should |
| 559 | + // be in SMW itself |
| 560 | + if ( $year < 0 ) { $year = ( $year * - 1 + 1 ) . " BC"; } |
| 561 | + $month = $actual_date->getMonth(); |
| 562 | + $day = $actual_date->getDay(); |
| 563 | + } |
| 564 | + } else { |
| 565 | + $cur_date = getdate(); |
| 566 | + $year = $cur_date['year']; |
| 567 | + $month = $cur_date['month']; |
| 568 | + $day = null; // no need for day |
| 569 | + } |
| 570 | + $text = ""; |
| 571 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 572 | + if ( $wgAmericanDates ) { |
| 573 | + $text .= SFFormInputs::monthDropdownHTML( $month, $input_name, $is_disabled ); |
| 574 | + $text .= ' <input tabindex="' . $sfgTabIndex . '" id="' . $input_id . '_day" name="' . $input_name . '[day]" type="text" value="' . $day . '" size="2" ' . $disabled_text . '/>' . "\n"; |
| 575 | + } else { |
| 576 | + $text .= ' <input tabindex="' . $sfgTabIndex . '" id="' . $input_id . '_day" name="' . $input_name . '[day]" type="text" value="' . $day . '" size="2" ' . $disabled_text . '/>' . "\n"; |
| 577 | + $text .= SFFormInputs::monthDropdownHTML( $month, $input_name, $is_disabled ); |
| 578 | + } |
| 579 | + $text .= ' <input tabindex="' . $sfgTabIndex . '" id="' . $input_id . '_year" name="' . $input_name . '[year]" type="text" value="' . $year . '" size="4" ' . $disabled_text . '/>' . "\n"; |
| 580 | + $text .= " <span id=\"$info_id\" class=\"errorMessage\"></span>"; |
| 581 | + return array( $text, null ); |
| 582 | + } |
| 583 | + |
| 584 | + static function dateTimeEntryHTML( $datetime, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 585 | + global $sfgTabIndex, $sfg24HourTime; |
| 586 | + |
| 587 | + $include_timezone = $other_args['include_timezone']; |
| 588 | + |
| 589 | + if ( $datetime ) { |
| 590 | + // can show up here either as an array or a string, depending on |
| 591 | + // whether it came from user input or a wiki page |
| 592 | + if ( is_array( $datetime ) ) { |
| 593 | + if ( isset( $datetime['hour'] ) ) $hour = $datetime['hour']; |
| 594 | + if ( isset( $datetime['minute'] ) ) $minute = $datetime['minute']; |
| 595 | + if ( isset( $datetime['second'] ) ) $second = $datetime['second']; |
| 596 | + if ( ! $sfg24HourTime ) { |
| 597 | + if ( isset( $datetime['ampm24h'] ) ) $ampm24h = $datetime['ampm24h']; |
| 598 | + } |
| 599 | + if ( isset( $datetime['timezone'] ) ) $timezone = $datetime['timezone']; |
| 600 | + } else { |
| 601 | + // TODO - this should change to use SMW's own date-handling class, |
| 602 | + // just like dateEntryHTML() does |
| 603 | + $actual_date = strtotime( $datetime ); |
| 604 | + if ( $sfg24HourTime ) { |
| 605 | + $hour = date( "G", $actual_date ); |
| 606 | + } else { |
| 607 | + $hour = date( "g", $actual_date ); |
| 608 | + } |
| 609 | + $minute = date( "i", $actual_date ); |
| 610 | + $second = date( "s", $actual_date ); |
| 611 | + if ( ! $sfg24HourTime ) { |
| 612 | + $ampm24h = date( "A", $actual_date ); |
| 613 | + } |
| 614 | + $timezone = date( "T", $actual_date ); |
| 615 | + } |
| 616 | + } else { |
| 617 | + $cur_date = getdate(); |
| 618 | + $hour = null; |
| 619 | + $minute = null; |
| 620 | + $second = "00"; // default at least this value |
| 621 | + $ampm24h = ""; |
| 622 | + $timezone = ""; |
| 623 | + } |
| 624 | + |
| 625 | + list( $text, $javascript_text ) = SFFormInputs::dateEntryHTML( $datetime, $input_name, $is_mandatory, $is_disabled, $other_args ); |
| 626 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 627 | + $text .= ' <input tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[hour]" type="text" value="' . $hour . '" size="2"/ ' . $disabled_text . '>'; |
| 628 | + $sfgTabIndex++; |
| 629 | + $text .= ' :<input tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[minute]" type="text" value="' . $minute . '" size="2"/ ' . $disabled_text . '>'; |
| 630 | + $sfgTabIndex++; |
| 631 | + $text .= ':<input tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[second]" type="text" value="' . $second . '" size="2"/ ' . $disabled_text . '>' . "\n"; |
| 632 | + |
| 633 | + if ( ! $sfg24HourTime ) { |
| 634 | + $sfgTabIndex++; |
| 635 | + $text .= ' <select tabindex="' . $sfgTabIndex . '" name="' . $input_name . "[ampm24h]\" $disabled_text>\n"; |
| 636 | + $ampm24h_options = array( '', 'AM', 'PM' ); |
| 637 | + foreach ( $ampm24h_options as $value ) { |
| 638 | + $text .= " <option value=\"$value\""; |
| 639 | + if ( $value == $ampm24h ) { $text .= " selected=\"selected\""; } |
| 640 | + $text .= ">$value</option>\n"; |
| 641 | + } |
| 642 | + $text .= " </select>\n"; |
| 643 | + } |
| 644 | + |
| 645 | + if ( $include_timezone ) { |
| 646 | + $sfgTabIndex++; |
| 647 | + $text .= ' <input tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[timezone]" type="text" value="' . $timezone . '" size="2"/ ' . $disabled_text . '>' . "\n"; |
| 648 | + } |
| 649 | + |
| 650 | + return array( $text, $javascript_text ); |
| 651 | + } |
| 652 | + |
| 653 | + static function radioButtonHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 654 | + global $sfgTabIndex, $sfgFieldNum; |
| 655 | + |
| 656 | + $input_id = "input_$sfgFieldNum"; |
| 657 | + $info_id = "info_$sfgFieldNum"; |
| 658 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 659 | + $check_set = false; |
| 660 | + $javascript_text = ''; |
| 661 | + $return_js_text = ''; |
| 662 | + if ( array_key_exists( 'show on select', $other_args ) ) { |
| 663 | + $javascript_text = 'onClick="'; |
| 664 | + foreach ( $other_args['show on select'] as $div_id => $options ) { |
| 665 | + $options_str = implode( "', '", $options ); |
| 666 | + $this_js_text = "showIfSelected('$input_id', ['$options_str'], '$div_id'); "; |
| 667 | + $javascript_text .= $this_js_text; |
| 668 | + $return_js_text .= $this_js_text . "\n"; |
| 669 | + } |
| 670 | + $javascript_text .= '"'; |
| 671 | + } |
| 672 | + $text = ""; |
| 673 | + // if it's mandatory, add a span around all the radiobuttons, since |
| 674 | + // some browsers don't support formatting of radiobuttons |
| 675 | + if ( $is_mandatory ) |
| 676 | + $text .= ' <span class="mandatoryFieldsSpan">' . "\n"; |
| 677 | + |
| 678 | + // start with an initial "None" value, unless this is a mandatory field |
| 679 | + // and there's a current value in place (either through a default value |
| 680 | + // or because we're editing an existing page) |
| 681 | + if ( ! $is_mandatory || $cur_value == '' ) { |
| 682 | + $text .= ' <input type="radio" id="' . $input_id . '" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '" value=""'; |
| 683 | + if ( ! $cur_value ) { |
| 684 | + $text .= ' checked="checked"'; |
| 685 | + $check_set = true; |
| 686 | + } |
| 687 | + $text .= " $disabled_text $javascript_text/> " . wfMsg( 'sf_formedit_none' ) . "\n"; |
| 688 | + } |
| 689 | + |
| 690 | + if ( ( $possible_values = $other_args['possible_values'] ) == null ) |
| 691 | + $possible_values = array(); |
| 692 | + foreach ( $possible_values as $i => $possible_value ) { |
| 693 | + $text .= ' <input type="radio" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '" value="' . $possible_value . '"'; |
| 694 | + if ( $cur_value == $possible_value || ( ! $cur_value && ! $check_set ) ) { |
| 695 | + $text .= ' checked="checked"'; |
| 696 | + $check_set = true; |
| 697 | + } |
| 698 | + if ( array_key_exists( 'value_labels', $other_args ) && is_array( $other_args['value_labels'] ) && array_key_exists( $possible_value, $other_args['value_labels'] ) ) |
| 699 | + $label = htmlspecialchars( $other_args['value_labels'][$possible_value] ); |
| 700 | + else |
| 701 | + $label = $possible_value; |
| 702 | + $text .= " $disabled_text $javascript_text/> $label\n"; |
| 703 | + } |
| 704 | + // close span |
| 705 | + if ( $is_mandatory ) |
| 706 | + $text .= " </span>"; |
| 707 | + $text .= <<<END |
| 708 | + <span id="$info_id" class="errorMessage"></span> |
| 709 | + |
| 710 | +END; |
| 711 | + return array( $text, $return_js_text ); |
| 712 | + } |
| 713 | + |
| 714 | + static function checkboxHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 715 | + global $sfgTabIndex, $sfgFieldNum; |
| 716 | + |
| 717 | + $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
| 718 | + if ( array_key_exists( 'class', $other_args ) ) |
| 719 | + $className .= " " . $other_args['class']; |
| 720 | + $info_id = "info_$sfgFieldNum"; |
| 721 | + $input_id = "input_$sfgFieldNum"; |
| 722 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 723 | + $return_js_text = ''; |
| 724 | + if ( array_key_exists( 'show on select', $other_args ) ) { |
| 725 | + $div_id = key( $other_args['show on select'] ); |
| 726 | + $this_js_text = "showIfChecked(['$input_id'], '$div_id');"; |
| 727 | + // we use addClickHandler(), instead of adding the Javascript via |
| 728 | + // onClick="", because MediaWiki's wikibits.js does its own handling |
| 729 | + // of checkboxes, which impacts their behavior in IE |
| 730 | + $return_js_text = <<<END |
| 731 | +$this_js_text; |
| 732 | +addClickHandler( |
| 733 | + document.getElementById("$input_id"), |
| 734 | + function() { $this_js_text } |
| 735 | +); |
| 736 | + |
| 737 | +END; |
| 738 | + } |
| 739 | + |
| 740 | + // can show up here either as an array or a string, depending on |
| 741 | + // whether it came from user input or a wiki page |
| 742 | + if ( is_array( $cur_value ) ) { |
| 743 | + $checked_str = ( array_key_exists( 'value', $cur_value ) && $cur_value['value'] == 'on' ) ? ' checked="checked"' : ""; |
| 744 | + } else { |
| 745 | + // default to false - no need to check if it matches a 'false' word |
| 746 | + $vlc = strtolower( trim( $cur_value ) ); |
| 747 | + // manually load SMW's message values, if they weren't loaded before |
| 748 | + wfLoadExtensionMessages( 'SemanticMediaWiki' ); |
| 749 | + if ( in_array( $vlc, explode( ',', wfMsgForContent( 'smw_true_words' ) ), TRUE ) ) { |
| 750 | + $checked_str = ' checked="checked"'; |
| 751 | + } else { |
| 752 | + $checked_str = ""; |
| 753 | + } |
| 754 | + } |
| 755 | + $text = <<<END |
| 756 | + <input name="{$input_name}[is_checkbox]" type="hidden" value="true" /> |
| 757 | + <input id="$input_id" name="{$input_name}[value]" type="checkbox" class="$className" tabindex="$sfgTabIndex" $checked_str $disabled_text/> |
| 758 | + <span id="$info_id" class="errorMessage"></span> |
| 759 | + |
| 760 | +END; |
| 761 | + return array( $text, $return_js_text ); |
| 762 | + } |
| 763 | + |
| 764 | + static function categoryHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 765 | + // escape if CategoryTree extension isn't included |
| 766 | + if ( ! function_exists( 'efCategoryTreeParserHook' ) ) |
| 767 | + return array( null, null ); |
| 768 | + |
| 769 | + global $sfgTabIndex, $sfgFieldNum; |
| 770 | + |
| 771 | + $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
| 772 | + if ( array_key_exists( 'class', $other_args ) ) |
| 773 | + $className .= " " . $other_args['class']; |
| 774 | + if ( array_key_exists( 'top category', $other_args ) ) { |
| 775 | + $top_category = $other_args['top category']; |
| 776 | + } else { |
| 777 | + // escape - we can't do anything |
| 778 | + return array( null, null ); |
| 779 | + } |
| 780 | + if ( array_key_exists( 'height', $other_args ) ) { |
| 781 | + $height = $other_args['height']; |
| 782 | + } else { |
| 783 | + $height = "100"; |
| 784 | + } |
| 785 | + if ( array_key_exists( 'width', $other_args ) ) { |
| 786 | + $width = $other_args['width']; |
| 787 | + } else { |
| 788 | + $width = "500"; |
| 789 | + } |
| 790 | + $input_id = "input_$sfgFieldNum"; |
| 791 | + $info_id = "info_$sfgFieldNum"; |
| 792 | + |
| 793 | + $text = '<div style="overflow: auto; padding: 5px; border: 1px #aaaaaa solid; max-height: ' . $height . 'px; width: ' . $width . 'px;">'; |
| 794 | + |
| 795 | + // start with an initial "None" value, unless this is a mandatory field |
| 796 | + // and there's a current value in place (either through a default value |
| 797 | + // or because we're editing an existing page) |
| 798 | + if ( ! $is_mandatory || $cur_value == '' ) { |
| 799 | + $input_id = "input_$sfgFieldNum"; |
| 800 | + $info_id = "info_$sfgFieldNum"; |
| 801 | + $text .= ' <input type="radio" id="' . $input_id . '" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '" value=""'; |
| 802 | + if ( ! $cur_value ) { |
| 803 | + $text .= ' checked="checked"'; |
| 804 | + $check_set = true; |
| 805 | + } |
| 806 | + $disabled_text = ( $is_disabled ) ? "disabled" : ""; |
| 807 | + $text .= " $disabled_text/> <em>" . wfMsg( 'sf_formedit_none' ) . "</em>\n"; |
| 808 | + } |
| 809 | + |
| 810 | + global $wgCategoryTreeMaxDepth; |
| 811 | + $wgCategoryTreeMaxDepth = 10; |
| 812 | + $tree = efCategoryTreeParserHook( $top_category, array( 'mode' => 'categories', 'depth' => 10 ) ); |
| 813 | + $tree = preg_replace( '/(<a class="CategoryTreeLabel.*>)(.*)(<\/a>)/', '<input id="' . $input_id . '" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '" value="$2" type="radio"> $1$2$3', $tree ); |
| 814 | + $tree = str_replace( "value=\"$cur_value\"", "value=\"$cur_value\" checked=\"checked\"", $tree ); |
| 815 | + // if it's disabled, set all to disabled |
| 816 | + if ( $is_disabled ) { |
| 817 | + $tree = str_replace( 'type="radio"', 'type="radio" disabled', $tree ); |
| 818 | + } |
| 819 | + $text .= $tree . '</div>'; |
| 820 | + |
| 821 | + $text .= <<<END |
| 822 | + <span id="$info_id" class="errorMessage"></span> |
| 823 | + |
| 824 | +END; |
| 825 | + |
| 826 | + return array( $text, null ); |
| 827 | + } |
| 828 | + |
| 829 | + static function categoriesHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) { |
| 830 | + // escape if CategoryTree extension isn't included |
| 831 | + if ( ! function_exists( 'efCategoryTreeParserHook' ) ) |
| 832 | + return array( null, null ); |
| 833 | + |
| 834 | + global $sfgTabIndex, $sfgFieldNum; |
| 835 | + |
| 836 | + $className = ( $is_mandatory ) ? "mandatoryField" : "createboxInput"; |
| 837 | + if ( array_key_exists( 'class', $other_args ) ) |
| 838 | + $className .= " " . $other_args['class']; |
| 839 | + $input_id = "input_$sfgFieldNum"; |
| 840 | + $info_id = "info_$sfgFieldNum"; |
| 841 | + $hidden_input_name = $input_name . "[is_list]"; |
| 842 | + // get list delimiter - default is comma |
| 843 | + if ( array_key_exists( 'delimiter', $other_args ) ) { |
| 844 | + $delimiter = $other_args['delimiter']; |
| 845 | + } else { |
| 846 | + $delimiter = ","; |
| 847 | + } |
| 848 | + $cur_values = self::getValuesArray( $cur_value, $delimiter ); |
| 849 | + if ( array_key_exists( 'top category', $other_args ) ) { |
| 850 | + $top_category = $other_args['top category']; |
| 851 | + } else { |
| 852 | + // escape - we can't do anything |
| 853 | + return array( null, null ); |
| 854 | + } |
| 855 | + if ( array_key_exists( 'height', $other_args ) ) { |
| 856 | + $height = $other_args['height']; |
| 857 | + } else { |
| 858 | + $height = "100"; |
| 859 | + } |
| 860 | + if ( array_key_exists( 'width', $other_args ) ) { |
| 861 | + $width = $other_args['width']; |
| 862 | + } else { |
| 863 | + $width = "500"; |
| 864 | + } |
| 865 | + |
| 866 | + global $wgCategoryTreeMaxDepth; |
| 867 | + $wgCategoryTreeMaxDepth = 10; |
| 868 | + $tree = efCategoryTreeParserHook( $top_category, array( 'mode' => 'categories', 'depth' => 10 ) ); |
| 869 | + // some string that will hopefully never show up in a category, template |
| 870 | + // or field name |
| 871 | + $dummy_str = 'REPLACE THIS STRING!'; |
| 872 | + $tree = preg_replace( '/(<a class="CategoryTreeLabel.*>)(.*)(<\/a>)/', '<input id="' . $input_id . '" tabindex="' . $sfgTabIndex . '" name="' . $input_name . '[' . $dummy_str . ']" value="$2" type="checkbox"> $1$2$3', $tree ); |
| 873 | + // replace values one at a time, by an incrementing index - |
| 874 | + // inspired by http://bugs.php.net/bug.php?id=11457 |
| 875 | + $i = 0; |
| 876 | + while ( ( $a = strpos( $tree, $dummy_str ) ) > 0 ) { |
| 877 | + $tree = substr( $tree, 0, $a ) . $i++ . substr( $tree, $a + strlen( $dummy_str ) ); |
| 878 | + } |
| 879 | + // set all checkboxes matching $cur_values to checked |
| 880 | + foreach ( $cur_values as $value ) { |
| 881 | + $tree = str_replace( "value=\"$value\"", "value=\"$value\" checked=\"checked\"", $tree ); |
| 882 | + } |
| 883 | + // if it's disabled, set all to disabled |
| 884 | + if ( $is_disabled ) { |
| 885 | + $tree = str_replace( 'type="checkbox"', 'type="checkbox" disabled', $tree ); |
| 886 | + } |
| 887 | + $text = '<div style="overflow: auto; padding: 5px; border: 1px #aaaaaa solid; max-height: ' . $height . 'px; width: ' . $width . 'px;">' . $tree . '</div>'; |
| 888 | + |
| 889 | + $text .= <<<END |
| 890 | + <input type="hidden" name="$hidden_input_name" value="1" /> |
| 891 | + |
| 892 | +END; |
| 893 | + |
| 894 | + return array( $text, null ); |
| 895 | + } |
| 896 | +} |
Property changes on: trunk/extensions/SemanticForms/includes/SF_FormInputs.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 897 | + native |
Index: trunk/extensions/SemanticForms/includes/SF_FormField.php |
— | — | @@ -0,0 +1,280 @@ |
| 2 | +<?php |
| 3 | +/* |
| 4 | + * This class is distinct from SFTemplateField in that it represents a |
| 5 | + * template field defined in a form - it contains a SFTemplateField object |
| 6 | + * within it (the $template_field variable), along with the other properties |
| 7 | + * for that field that are set within the form |
| 8 | + */ |
| 9 | +class SFFormField { |
| 10 | + var $num; |
| 11 | + var $template_field; |
| 12 | + var $input_type; |
| 13 | + var $is_mandatory; |
| 14 | + var $is_hidden; |
| 15 | + var $is_restricted; |
| 16 | + var $possible_values; |
| 17 | + // the following fields are not set by the form-creation page |
| 18 | + // (though they could be) |
| 19 | + var $is_uploadable; |
| 20 | + var $field_args; |
| 21 | + var $autocomplete_source; |
| 22 | + var $autocomplete_field_type; |
| 23 | + var $no_autocomplete; |
| 24 | + var $part_of_multiple; |
| 25 | + // somewhat of a hack - these two fields are for a field in a specific |
| 26 | + // representation of a form, not the form definition; ideally these |
| 27 | + // should be contained in a third 'field' class, called something like |
| 28 | + // SFFormInstanceField, that holds these fields plus an instance of |
| 29 | + // SFFormField. Too much work? |
| 30 | + var $input_name; |
| 31 | + var $is_disabled; |
| 32 | + |
| 33 | + static function create( $num, $template_field ) { |
| 34 | + $f = new SFFormField(); |
| 35 | + $f->num = $num; |
| 36 | + $f->template_field = $template_field; |
| 37 | + $f->input_type = ""; |
| 38 | + $f->is_mandatory = false; |
| 39 | + $f->is_hidden = false; |
| 40 | + $f->is_restricted = false; |
| 41 | + $f->is_uploadable = false; |
| 42 | + $f->possible_values = null; |
| 43 | + return $f; |
| 44 | + } |
| 45 | + |
| 46 | + static function createFromDefinition( $field_name, $input_name, $is_mandatory, $is_hidden, $is_uploadable, $possible_values, $is_disabled, $is_list, $input_type, $field_args, $all_fields, $strict_parsing ) { |
| 47 | + // see if this field matches one of the fields defined for this |
| 48 | + // template - if it is, use all available information about |
| 49 | + // that field; if it's not, either include it in the form or |
| 50 | + // not, depending on whether the template has a 'strict' |
| 51 | + // setting in the form definition |
| 52 | + $the_field = null; |
| 53 | + foreach ( $all_fields as $cur_field ) { |
| 54 | + if ( $field_name == $cur_field->field_name ) { |
| 55 | + $the_field = $cur_field; |
| 56 | + break; |
| 57 | + } |
| 58 | + } |
| 59 | + if ( $the_field == null ) { |
| 60 | + if ( $strict_parsing ) { |
| 61 | + $dummy_ff = new SFFormField(); |
| 62 | + $dummy_ff->template_field = new SFTemplateField(); |
| 63 | + $dummy_ff->is_list = false; |
| 64 | + $dummy_ff->field_args = array(); |
| 65 | + return $dummy_ff; |
| 66 | + } |
| 67 | + $the_field = new SFTemplateField(); |
| 68 | + } |
| 69 | + |
| 70 | + // create an SFFormField object, containing this field as well |
| 71 | + // as settings from the form definition file |
| 72 | + $f = new SFFormField(); |
| 73 | + $f->template_field = $the_field; |
| 74 | + $f->is_mandatory = $is_mandatory; |
| 75 | + $f->is_hidden = $is_hidden; |
| 76 | + $f->is_uploadable = $is_uploadable; |
| 77 | + $f->possible_values = $possible_values; |
| 78 | + $f->input_type = $input_type; |
| 79 | + $f->field_args = $field_args; |
| 80 | + $f->input_name = $input_name; |
| 81 | + $f->is_disabled = $is_disabled; |
| 82 | + $f->is_list = $is_list; |
| 83 | + return $f; |
| 84 | + } |
| 85 | + |
| 86 | + /** |
| 87 | + * Get the set of possible form input types for either a specific |
| 88 | + * SMW property type or a list of such types |
| 89 | + */ |
| 90 | + function possibleInputTypes( $semantic_type, $is_list ) { |
| 91 | + // first, get the list of field types, to determine which one this is |
| 92 | + global $smwgContLang; |
| 93 | + $datatypeLabels = $smwgContLang->getDatatypeLabels(); |
| 94 | + $string_type = $datatypeLabels['_str']; |
| 95 | + $text_type = $datatypeLabels['_txt']; |
| 96 | + // type introduced in SMW 1.2 |
| 97 | + $code_type = array_key_exists( '_cod', $datatypeLabels ) ? $datatypeLabels['_cod'] : 'code'; |
| 98 | + $url_type = $datatypeLabels['_uri']; |
| 99 | + $email_type = $datatypeLabels['_ema']; |
| 100 | + $number_type = $datatypeLabels['_num']; |
| 101 | + $bool_type = $datatypeLabels['_boo']; |
| 102 | + $date_type = $datatypeLabels['_dat']; |
| 103 | + $enum_type = 'enumeration'; // not a real type |
| 104 | + $page_type = $datatypeLabels['_wpg']; |
| 105 | + |
| 106 | + // then, return the array of possible input types, depending on |
| 107 | + // the field type and whether this field will contain multiple |
| 108 | + // values |
| 109 | + if ( $semantic_type == $string_type || |
| 110 | + $semantic_type == $number_type || |
| 111 | + $semantic_type == $url_type || |
| 112 | + $semantic_type == $email_type ) { |
| 113 | + if ( $is_list ) { |
| 114 | + return array( 'text', 'textarea', 'categories' ); |
| 115 | + } else { |
| 116 | + return array( 'text', 'category' ); |
| 117 | + } |
| 118 | + } elseif ( $semantic_type == $text_type || $semantic_type == $code_type ) { |
| 119 | + return array( 'textarea' ); |
| 120 | + } elseif ( $semantic_type == $bool_type ) { |
| 121 | + return array( 'checkbox' ); |
| 122 | + } elseif ( $semantic_type == $date_type ) { |
| 123 | + return array( 'date', 'datetime', 'datetime with timezone', 'year' ); |
| 124 | + } elseif ( $semantic_type == $enum_type ) { |
| 125 | + if ( $is_list ) { |
| 126 | + return array( 'checkboxes', 'listbox' ); |
| 127 | + } else { |
| 128 | + return array( 'dropdown', 'radiobutton' ); |
| 129 | + } |
| 130 | + } elseif ( $semantic_type == $page_type ) { |
| 131 | + if ( $is_list ) { |
| 132 | + return array( 'text', 'textarea' ); |
| 133 | + } else { |
| 134 | + return array( 'text' ); |
| 135 | + } |
| 136 | + } else { // blank or an unknown type |
| 137 | + return array( 'text', 'textarea', 'checkbox', 'date', 'datetime', 'datetime with timezone', 'category', 'categories' ); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + function inputTypeDropdownHTML( $dropdown_name, $possible_input_types, $cur_input_type ) { |
| 142 | + // create the dropdown HTML for a list of possible input types |
| 143 | + $text = " <select name=\"$dropdown_name\">\n"; |
| 144 | + foreach ( $possible_input_types as $i => $input_type ) { |
| 145 | + if ( $i == 0 ) { |
| 146 | + $text .= " <option value=\"\">$input_type " . |
| 147 | + wfMsg( 'sf_createform_inputtypedefault' ) . "</option>\n"; |
| 148 | + } else { |
| 149 | + $selected_str = ( $cur_input_type == $input_type ) ? "selected" : ""; |
| 150 | + $text .= " <option value=\"$input_type\" $selected_str>$input_type</option>\n"; |
| 151 | + } |
| 152 | + } |
| 153 | + $text .= " </select>\n"; |
| 154 | + return $text; |
| 155 | + } |
| 156 | + |
| 157 | + function creationHTML( $template_num ) { |
| 158 | + $field_form_text = $template_num . "_" . $this->num; |
| 159 | + $template_field = $this->template_field; |
| 160 | + $text = '<h3>' . wfMsg( 'sf_createform_field' ) . " '" . $template_field->field_name . "'</h3>\n"; |
| 161 | + $prop_link_text = SFUtils::linkText( SMW_NS_PROPERTY, $template_field->semantic_property ); |
| 162 | + // TODO - remove this probably-unnecessary check? |
| 163 | + if ( $template_field->semantic_property == "" ) { |
| 164 | + // print nothing if there's no semantic field |
| 165 | + } elseif ( $template_field->field_type == "" ) { |
| 166 | + $text .= '<p>' . wfMsg( 'sf_createform_fieldpropunknowntype', $prop_link_text ) . "</p>\n"; |
| 167 | + } elseif ( $template_field->is_list ) { |
| 168 | + $text .= '<p>' . wfMsg( 'sf_createform_fieldproplist', $prop_link_text, |
| 169 | + SFUtils::linkText( SMW_NS_TYPE, $template_field->field_type ) ) . "</p>\n"; |
| 170 | + } else { |
| 171 | + $text .= '<p>' . wfMsg( 'sf_createform_fieldprop', $prop_link_text, |
| 172 | + SFUtils::linkText( SMW_NS_TYPE, $template_field->field_type ) ) . "</p>\n"; |
| 173 | + } |
| 174 | + // if it's not a semantic field - don't add any text |
| 175 | + $form_label_text = wfMsg( 'sf_createform_formlabel' ); |
| 176 | + $field_label = $template_field->label; |
| 177 | + $input_type_text = wfMsg( 'sf_createform_inputtype' ); |
| 178 | + $text .= <<<END |
| 179 | + <p>$form_label_text <input type="text" name="label_$field_form_text" size=20 value="$field_label" /> |
| 180 | + $input_type_text |
| 181 | + |
| 182 | +END; |
| 183 | + $possible_input_types = $this->possibleInputTypes( $template_field->field_type, $template_field->is_list ); |
| 184 | + if ( count( $possible_input_types ) > 1 ) { |
| 185 | + $text .= $this->inputTypeDropdownHTML( "input_type_$field_form_text", $possible_input_types, $template_field->input_type ); |
| 186 | + } else { |
| 187 | + $text .= $possible_input_types[0]; |
| 188 | + } |
| 189 | + $mandatory_checked_str = ( $this->is_mandatory ) ? "checked" : ""; |
| 190 | + $mandatory_text = wfMsg( 'sf_createform_mandatory' ); |
| 191 | + $hidden_checked_str = ( $this->is_hidden ) ? "checked" : ""; |
| 192 | + $hidden_text = wfMsg( 'sf_createform_hidden' ); |
| 193 | + $restricted_checked_str = ( $this->is_restricted ) ? "checked" : ""; |
| 194 | + $restricted_text = wfMsg( 'sf_createform_restricted' ); |
| 195 | + $text .= <<<END |
| 196 | + </p> |
| 197 | + <p> |
| 198 | + <input type="checkbox" name="mandatory_$field_form_text" value="mandatory" $mandatory_checked_str /> $mandatory_text |
| 199 | + <input type="checkbox" name="hidden_$field_form_text" value="hidden" $hidden_checked_str /> $hidden_text |
| 200 | + <input type="checkbox" name="restricted_$field_form_text" value="restricted" $restricted_checked_str /> $restricted_text</p> |
| 201 | + <hr> |
| 202 | + |
| 203 | +END; |
| 204 | + return $text; |
| 205 | + } |
| 206 | + |
| 207 | + // for now, HTML of an individual field depends on whether or not it's |
| 208 | + // part of multiple-instance template; this may change if handling of |
| 209 | + // such templates in form definitions gets more sophisticated |
| 210 | + function createMarkup( $part_of_multiple, $is_last_field_in_template ) { |
| 211 | + $text = ""; |
| 212 | + if ( $this->template_field->label != "" ) { |
| 213 | + if ( $part_of_multiple ) { |
| 214 | + $text .= "'''" . $this->template_field->label . ":''' "; |
| 215 | + } else { |
| 216 | + $text .= "! " . $this->template_field->label . ":\n"; |
| 217 | + } |
| 218 | + } |
| 219 | + if ( ! $part_of_multiple ) { $text .= "| "; } |
| 220 | + $text .= "{{{field|" . $this->template_field->field_name; |
| 221 | + if ( isset( $this->template_field->input_type ) && |
| 222 | + $this->template_field->input_type != null ) { |
| 223 | + $text .= "|input type=" . $this->template_field->input_type; |
| 224 | + } |
| 225 | + if ( $this->is_mandatory ) { |
| 226 | + $text .= "|mandatory"; |
| 227 | + } elseif ( $this->is_hidden ) { |
| 228 | + $text .= "|hidden"; |
| 229 | + } elseif ( $this->is_restricted ) { |
| 230 | + $text .= "|restricted"; |
| 231 | + } |
| 232 | + $text .= "}}}\n"; |
| 233 | + if ( $part_of_multiple ) { |
| 234 | + $text .= "\n"; |
| 235 | + } elseif ( ! $is_last_field_in_template ) { |
| 236 | + $text .= "|-\n"; |
| 237 | + } |
| 238 | + return $text; |
| 239 | + } |
| 240 | + |
| 241 | + /* |
| 242 | + * Since Semantic Forms uses a hook system for the functions that |
| 243 | + * create HTML inputs, most arguments are contained in the "$other_args" |
| 244 | + * array - create this array, using the attributes of this form |
| 245 | + * field and the template field it corresponds to, if any |
| 246 | + */ |
| 247 | + function getArgumentsForInputCall( $default_args = null ) { |
| 248 | + // start with the arguments array already defined |
| 249 | + $other_args = $this->field_args; |
| 250 | + // a value defined for the form field should always supersede |
| 251 | + // the coresponding value for the template field |
| 252 | + if ( $this->possible_values != null ) |
| 253 | + $other_args['possible_values'] = $this->possible_values; |
| 254 | + else { |
| 255 | + $other_args['possible_values'] = $this->template_field->possible_values; |
| 256 | + $other_args['value_labels'] = $this->template_field->value_labels; |
| 257 | + } |
| 258 | + $other_args['is_list'] = ( $this->is_list || $this->template_field->is_list ); |
| 259 | + if ( $this->template_field->semantic_property != '' && ! array_key_exists( 'semantic_property', $other_args ) ) |
| 260 | + $other_args['semantic_property'] = $this->template_field->semantic_property; |
| 261 | + // if autocompletion hasn't already been hardcoded in the form, |
| 262 | + // and it's a property of type page, or a property of another |
| 263 | + // type with 'autocomplete' specified, set the necessary |
| 264 | + // parameters |
| 265 | + if ( ! array_key_exists( 'autocompletion source', $other_args ) ) { |
| 266 | + if ( $this->template_field->propertyIsOfType( '_wpg' ) ) { |
| 267 | + $other_args['autocompletion source'] = $this->template_field->semantic_property; |
| 268 | + $other_args['autocomplete field type'] = 'relation'; |
| 269 | + } elseif ( array_key_exists( 'autocomplete', $other_args ) || array_key_exists( 'remote autocompletion', $other_args ) ) { |
| 270 | + $other_args['autocompletion source'] = $this->template_field->semantic_property; |
| 271 | + $other_args['autocomplete field type'] = 'attribute'; |
| 272 | + } |
| 273 | + } |
| 274 | + // now merge in the default values set by SFFormPrinter, if |
| 275 | + // there were any - put the default values first, so that if |
| 276 | + // there's a conflict they'll be overridden |
| 277 | + if ( $default_args != null ) |
| 278 | + $other_args = array_merge( $default_args, $other_args ); |
| 279 | + return $other_args; |
| 280 | + } |
| 281 | +} |
Property changes on: trunk/extensions/SemanticForms/includes/SF_FormField.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 282 | + native |
Index: trunk/extensions/SemanticForms/includes/SF_FormPrinter.php |
— | — | @@ -0,0 +1,1409 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Handles the creation and running of a user-created form. |
| 5 | + * |
| 6 | + * @author Yaron Koren |
| 7 | + * @author Nils Oppermann |
| 8 | + * @author Jeffrey Stuckman |
| 9 | + * @author Harold Solbrig |
| 10 | + * @author Daniel Hansch |
| 11 | + */ |
| 12 | + |
| 13 | +class SFFormPrinter { |
| 14 | + |
| 15 | + var $mSemanticTypeHooks; |
| 16 | + var $mInputTypeHooks; |
| 17 | + var $standardInputsIncluded; |
| 18 | + var $mPageTitle; |
| 19 | + |
| 20 | + function SFFormPrinter() { |
| 21 | + global $smwgContLang; |
| 22 | + |
| 23 | + // initialize the set of hooks for the entry-field functions to call for |
| 24 | + // fields of both a specific semantic "type" and a defined "input type" |
| 25 | + // in the form definition |
| 26 | + $this->mSemanticTypeHooks = array(); |
| 27 | + if ( $smwgContLang != null ) { |
| 28 | + $datatypeLabels = $smwgContLang->getDatatypeLabels(); |
| 29 | + $string_type = $datatypeLabels['_str']; |
| 30 | + $text_type = $datatypeLabels['_txt']; |
| 31 | + // type introduced in SMW 1.2 |
| 32 | + if ( array_key_exists( '_cod', $datatypeLabels ) ) |
| 33 | + $code_type = $datatypeLabels['_cod']; |
| 34 | + else |
| 35 | + $code_type = 'code'; |
| 36 | + $url_type = $datatypeLabels['_uri']; |
| 37 | + $email_type = $datatypeLabels['_ema']; |
| 38 | + $number_type = $datatypeLabels['_num']; |
| 39 | + $bool_type = $datatypeLabels['_boo']; |
| 40 | + $date_type = $datatypeLabels['_dat']; |
| 41 | + $enum_type = 'enumeration'; // not a real type |
| 42 | + $page_type = $datatypeLabels['_wpg']; |
| 43 | + $this->setSemanticTypeHook( $string_type, false, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'string' ) ); |
| 44 | + $this->setSemanticTypeHook( $string_type, true, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'string', 'is_list' => 'true', 'size' => '100' ) ); |
| 45 | + $this->setSemanticTypeHook( $text_type, false, array( 'SFFormInputs', 'textAreaHTML' ), array() ); |
| 46 | + $this->setSemanticTypeHook( $code_type, false, array( 'SFFormInputs', 'textAreaHTML' ), array() ); |
| 47 | + $this->setSemanticTypeHook( $url_type, false, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'URL' ) ); |
| 48 | + $this->setSemanticTypeHook( $email_type, false, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'email' ) ); |
| 49 | + $this->setSemanticTypeHook( $number_type, false, array( 'SFFormInputs', 'textEntryHTML' ), array( 'field_type' => 'number' ) ); |
| 50 | + $this->setSemanticTypeHook( $bool_type, false, array( 'SFFormInputs', 'checkboxHTML' ), array() ); |
| 51 | + $this->setSemanticTypeHook( $date_type, false, array( 'SFFormInputs', 'dateEntryHTML' ), array() ); |
| 52 | + $this->setSemanticTypeHook( $enum_type, false, array( 'SFFormInputs', 'dropdownHTML' ), array() ); |
| 53 | + $this->setSemanticTypeHook( $enum_type, true, array( 'SFFormInputs', 'checkboxesHTML' ), array() ); |
| 54 | + $this->setSemanticTypeHook( $page_type, false, array( 'SFFormInputs', 'textInputWithAutocompleteHTML' ), array( 'field_type' => 'page' ) ); |
| 55 | + $this->setSemanticTypeHook( $page_type, true, array( 'SFFormInputs', 'textInputWithAutocompleteHTML' ), array( 'field_type' => 'page', 'size' => '100', 'is_list' => 'true' ) ); |
| 56 | + } |
| 57 | + $this->mInputTypeHooks = array(); |
| 58 | + $this->setInputTypeHook( 'text', array( 'SFFormInputs', 'textEntryHTML' ), array() ); |
| 59 | + $this->setInputTypeHook( 'textarea', array( 'SFFormInputs', 'textAreaHTML' ), array() ); |
| 60 | + $this->setInputTypeHook( 'date', array( 'SFFormInputs', 'dateEntryHTML' ), array() ); |
| 61 | + $this->setInputTypeHook( 'datetime', array( 'SFFormInputs', 'dateTimeEntryHTML' ), array( 'include_timezone' => false ) ); |
| 62 | + $this->setInputTypeHook( 'datetime with timezone', array( 'SFFormInputs', 'dateTimeEntryHTML' ), array( 'include_timezone' => true ) ); |
| 63 | + $this->setInputTypeHook( 'year', array( 'SFFormInputs', 'textEntryHTML' ), array( 'size' => 4 ) ); |
| 64 | + $this->setInputTypeHook( 'checkbox', array( 'SFFormInputs', 'checkboxHTML' ), array() ); |
| 65 | + $this->setInputTypeHook( 'radiobutton', array( 'SFFormInputs', 'radioButtonHTML' ), array() ); |
| 66 | + $this->setInputTypeHook( 'checkboxes', array( 'SFFormInputs', 'checkboxesHTML' ), array() ); |
| 67 | + $this->setInputTypeHook( 'listbox', array( 'SFFormInputs', 'listboxHTML' ), array() ); |
| 68 | + $this->setInputTypeHook( 'category', array( 'SFFormInputs', 'categoryHTML' ), array() ); |
| 69 | + $this->setInputTypeHook( 'categories', array( 'SFFormInputs', 'categoriesHTML' ), array() ); |
| 70 | + |
| 71 | + // initialize other variables |
| 72 | + $this->standardInputsIncluded = false; |
| 73 | + } |
| 74 | + |
| 75 | + function setSemanticTypeHook( $type, $is_list, $function_name, $default_args ) { |
| 76 | + $this->mSemanticTypeHooks[$type][$is_list] = array( $function_name, $default_args ); |
| 77 | + } |
| 78 | + |
| 79 | + function setInputTypeHook( $input_type, $function_name, $default_args ) { |
| 80 | + $this->mInputTypeHooks[$input_type] = array( $function_name, $default_args ); |
| 81 | + } |
| 82 | + |
| 83 | + |
| 84 | + /** |
| 85 | + * Show the set of previous deletions for the page being added. |
| 86 | + * This function is copied almost exactly from EditPage::showDeletionLog() - |
| 87 | + * unfortunately, neither that function nor Article::showDeletionLog() can |
| 88 | + * be called from here, since they're both protected |
| 89 | + */ |
| 90 | + function showDeletionLog( $out ) { |
| 91 | + // if MW doesn't have LogEventsList defined, exit immediately |
| 92 | + if ( ! class_exists( 'LogEventsList' ) ) |
| 93 | + return false; |
| 94 | + |
| 95 | + global $wgUser; |
| 96 | + $loglist = new LogEventsList( $wgUser->getSkin(), $out ); |
| 97 | + $pager = new LogPager( $loglist, 'delete', false, $this->mPageTitle->getPrefixedText() ); |
| 98 | + $count = $pager->getNumRows(); |
| 99 | + if ( $count > 0 ) { |
| 100 | + $pager->mLimit = 10; |
| 101 | + $out->addHTML( '<div class="mw-warning-with-logexcerpt">' ); |
| 102 | + // the message name changed in MW 1.16 |
| 103 | + if ( ! wfEmptyMsg( 'moveddeleted-notice', wfMsg( 'moveddeleted-notice' ) ) ) |
| 104 | + $out->addWikiMsg( 'moveddeleted-notice' ); |
| 105 | + else |
| 106 | + $out->addWikiMsg( 'recreate-deleted-warn' ); |
| 107 | + $out->addHTML( |
| 108 | + $loglist->beginLogEventsList() . |
| 109 | + $pager->getBody() . |
| 110 | + $loglist->endLogEventsList() |
| 111 | + ); |
| 112 | + if ( $count > 10 ) { |
| 113 | + $out->addHTML( $wgUser->getSkin()->link( |
| 114 | + SpecialPage::getTitleFor( 'Log' ), |
| 115 | + wfMsgHtml( 'deletelog-fulllog' ), |
| 116 | + array(), |
| 117 | + array( |
| 118 | + 'type' => 'delete', |
| 119 | + 'page' => $this->mPageTitle->getPrefixedText() ) ) ); |
| 120 | + } |
| 121 | + $out->addHTML( '</div>' ); |
| 122 | + return true; |
| 123 | + } |
| 124 | + |
| 125 | + return false; |
| 126 | + } |
| 127 | + |
| 128 | + function formHTML( $form_def, $form_submitted, $source_is_page, $form_id = null, $existing_page_content = null, $page_name = null, $page_name_formula = null, $is_query = false, $embedded = false ) { |
| 129 | + global $wgRequest, $wgUser, $wgParser; |
| 130 | + global $sfgTabIndex; // used to represent the current tab index in the form |
| 131 | + global $sfgFieldNum; // used for setting various HTML IDs |
| 132 | + global $sfgJSValidationCalls; // array of Javascript calls to determine if page can be saved |
| 133 | + |
| 134 | + // initialize some variables |
| 135 | + $sfgTabIndex = 1; |
| 136 | + $sfgFieldNum = 1; |
| 137 | + $source_page_matches_this_form = false; |
| 138 | + $form_page_title = NULL; |
| 139 | + $generated_page_name = $page_name_formula; |
| 140 | + // $form_is_partial is true if: |
| 141 | + // (a) 'partial' == 1 in the arguments |
| 142 | + // (b) 'partial form' is found in the form definition |
| 143 | + // in the latter case, it may remain false until close to the end of |
| 144 | + // the parsing, so we have to assume that it will become a possibility |
| 145 | + $form_is_partial = false; |
| 146 | + $new_text = ""; |
| 147 | + // flag for placing "<onlyinclude>" tags in form output |
| 148 | + $onlyinclude_free_text = false; |
| 149 | + |
| 150 | + // if we have existing content and we're not in an active replacement |
| 151 | + // situation, preserve the original content. We do this because we want |
| 152 | + // to pass the original content on IF this is a partial form |
| 153 | + // TODO: A better approach here would be to pass the revision id of the |
| 154 | + // existing page content through the replace value, which would |
| 155 | + // minimize the html traffic and would allow us to do a concurrent |
| 156 | + // update check. For now, we pass it through the hidden text field... |
| 157 | + |
| 158 | + if ( ! $wgRequest->getCheck( 'partial' ) ) { |
| 159 | + $original_page_content = $existing_page_content; |
| 160 | + } else { |
| 161 | + $original_page_content = null; |
| 162 | + if ( $wgRequest->getCheck( 'free_text' ) ) { |
| 163 | + $existing_page_content = $wgRequest->getVal( 'free_text' ); |
| 164 | + $form_is_partial = true; |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + // disable all form elements if user doesn't have edit permission - |
| 169 | + // two different checks are needed, because editing permissions can be |
| 170 | + // set in different ways |
| 171 | + // HACK - sometimes we don't know the page name in advance, but we still |
| 172 | + // need to set a title here for testing permissions |
| 173 | + if ( $page_name == '' ) |
| 174 | + $this->mPageTitle = Title::newFromText( |
| 175 | + $wgRequest->getVal( 'namespace' ) . ":Semantic Forms permissions test" ); |
| 176 | + else |
| 177 | + $this->mPageTitle = Title::newFromText( $page_name ); |
| 178 | + global $wgOut; |
| 179 | + // show previous set of deletions for this page, if it's been deleted before |
| 180 | + if ( ! $form_submitted && ! $this->mPageTitle->exists() ) { |
| 181 | + $this->showDeletionLog( $wgOut ); |
| 182 | + } |
| 183 | + $user_can_edit_page = ( $wgUser->isAllowed( 'edit' ) && $this->mPageTitle->userCan( 'edit' ) ); |
| 184 | + wfRunHooks( 'sfUserCanEditPage', array( &$user_can_edit_page ) ); |
| 185 | + if ( $user_can_edit_page || $is_query ) { |
| 186 | + $form_is_disabled = false; |
| 187 | + $form_text = ""; |
| 188 | + // show "Your IP address will be recorded" warning if user is |
| 189 | + // anonymous, and it's not a query - |
| 190 | + // wikitext for bolding has to be replaced with HTML |
| 191 | + if ( $wgUser->isAnon() && ! $is_query ) { |
| 192 | + $anon_edit_warning = preg_replace( "/'''(.*)'''/", "<strong>$1</strong>", wfMsg( 'anoneditwarning' ) ); |
| 193 | + $form_text .= "<p>$anon_edit_warning</p>\n"; |
| 194 | + } |
| 195 | + } else { |
| 196 | + $form_is_disabled = true; |
| 197 | + // display a message to the user explaining why they can't edit the |
| 198 | + // page - borrowed heavily from EditPage.php |
| 199 | + if ( $wgUser->isAnon() ) { |
| 200 | + $skin = $wgUser->getSkin(); |
| 201 | + $loginTitle = SpecialPage::getTitleFor( 'Userlogin' ); |
| 202 | + $loginLink = $skin->makeKnownLinkObj( $loginTitle, wfMsgHtml( 'loginreqlink' ) ); |
| 203 | + $form_text = wfMsgWikiHtml( 'whitelistedittext', $loginLink ); |
| 204 | + } else { |
| 205 | + $form_text = wfMsg( 'protectedpagetext' ); |
| 206 | + } |
| 207 | + } |
| 208 | + $javascript_text = ""; |
| 209 | + $sfgJSValidationCalls = array(); |
| 210 | + $fields_javascript_text = ""; |
| 211 | + |
| 212 | + // Remove <noinclude> sections and <includeonly> tags from form definition |
| 213 | + $form_def = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $form_def ); |
| 214 | + $form_def = strtr( $form_def, array( '<includeonly>' => '', '</includeonly>' => '' ) ); |
| 215 | + |
| 216 | + // parse wiki-text |
| 217 | + // add '<nowiki>' tags around every triple-bracketed form definition |
| 218 | + // element, so that the wiki parser won't touch it - the parser will |
| 219 | + // remove the '<nowiki>' tags, leaving us with what we need |
| 220 | + $form_def = "__NOEDITSECTION__" . strtr( $form_def, array( '{{{' => '<nowiki>{{{', '}}}' => '}}}</nowiki>' ) ); |
| 221 | + $old_strip_state = $wgParser->mStripState; |
| 222 | + $wgParser->mStripState = new StripState(); |
| 223 | + $wgParser->mOptions = new ParserOptions(); |
| 224 | + $wgParser->mOptions->initialiseFromUser( $wgUser ); |
| 225 | + |
| 226 | + // get the form definition from the cache, if we're using caching and it's |
| 227 | + // there |
| 228 | + $got_form_def_from_cache = false; |
| 229 | + global $sfgCacheFormDefinitions; |
| 230 | + if ( $sfgCacheFormDefinitions && ! is_null( $form_id ) ) { |
| 231 | + $db = wfGetDB( DB_MASTER ); |
| 232 | + $res = $db->select( 'page_props', 'pp_value', "pp_propname = 'formdefinition' AND pp_page = '$form_id'" ); |
| 233 | + if ( $res->numRows() > 0 ) { |
| 234 | + $form_def = $res->fetchObject()->pp_value; |
| 235 | + $got_form_def_from_cache = true; |
| 236 | + } |
| 237 | + } |
| 238 | + // otherwise, parse it |
| 239 | + if ( ! $got_form_def_from_cache ) |
| 240 | + $form_def = $wgParser->parse( $form_def, $this->mPageTitle, $wgParser->mOptions )->getText(); |
| 241 | + $wgParser->mStripState = $old_strip_state; |
| 242 | + |
| 243 | + // turn form definition file into an array of sections, one for each |
| 244 | + // template definition (plus the first section) |
| 245 | + $form_def_sections = array(); |
| 246 | + $start_position = 0; |
| 247 | + $section_start = 0; |
| 248 | + $free_text_was_included = false; |
| 249 | + $free_text_preload_page = null; |
| 250 | + $free_text_components = array(); |
| 251 | + $all_values_for_template = array(); |
| 252 | + // unencode and HTML-encoded representations of curly brackets and |
| 253 | + // pipes - this is a hack to allow for forms to include templates |
| 254 | + // that themselves contain form elements - the escaping is needed |
| 255 | + // to make sure that those elements don't get parsed too early |
| 256 | + $form_def = str_replace( array( '{', '|', '}' ), array( '{', '|', '}' ), $form_def ); |
| 257 | + // and another hack - replace the 'free text' standard input with |
| 258 | + // a field declaration to get it to be handled as a field |
| 259 | + $form_def = str_replace( 'standard input|free text', 'field|<freetext>', $form_def ); |
| 260 | + while ( $brackets_loc = strpos( $form_def, "{{{", $start_position ) ) { |
| 261 | + $brackets_end_loc = strpos( $form_def, "}}}", $brackets_loc ); |
| 262 | + $bracketed_string = substr( $form_def, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) ); |
| 263 | + $tag_components = explode( '|', $bracketed_string ); |
| 264 | + $tag_title = trim( $tag_components[0] ); |
| 265 | + if ( $tag_title == 'for template' || $tag_title == 'end template' ) { |
| 266 | + // create a section for everything up to here |
| 267 | + $section = substr( $form_def, $section_start, $brackets_loc - $section_start ); |
| 268 | + $form_def_sections[] = $section; |
| 269 | + $section_start = $brackets_loc; |
| 270 | + } |
| 271 | + $start_position = $brackets_loc + 1; |
| 272 | + } // end while |
| 273 | + $form_def_sections[] = trim( substr( $form_def, $section_start ) ); |
| 274 | + |
| 275 | + // cycle through form definition file (and possibly an existing article |
| 276 | + // as well), finding template and field declarations and replacing them |
| 277 | + // with form elements, either blank or pre-populated, as appropriate |
| 278 | + $all_fields = array(); |
| 279 | + $data_text = ""; |
| 280 | + $template_name = ""; |
| 281 | + $allow_multiple = false; |
| 282 | + $instance_num = 0; |
| 283 | + $all_instances_printed = false; |
| 284 | + $strict_parsing = false; |
| 285 | + // initialize list of choosers (dropdowns with available templates) |
| 286 | + $choosers = array(); |
| 287 | + for ( $section_num = 0; $section_num < count( $form_def_sections ); $section_num++ ) { |
| 288 | + $tif = new SFTemplateInForm(); |
| 289 | + $start_position = 0; |
| 290 | + $template_text = ""; |
| 291 | + // the append is there to ensure that the original array doesn't get |
| 292 | + // modified; is it necessary? |
| 293 | + $section = " " . $form_def_sections[$section_num]; |
| 294 | + |
| 295 | + while ( $brackets_loc = strpos( $section, '{{{', $start_position ) ) { |
| 296 | + $brackets_end_loc = strpos( $section, "}}}", $brackets_loc ); |
| 297 | + $bracketed_string = substr( $section, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) ); |
| 298 | + $tag_components = explode( '|', $bracketed_string ); |
| 299 | + $tag_title = trim( $tag_components[0] ); |
| 300 | + // ===================================================== |
| 301 | + // for template processing |
| 302 | + // ===================================================== |
| 303 | + if ( $tag_title == 'for template' ) { |
| 304 | + $old_template_name = $template_name; |
| 305 | + $template_name = trim( $tag_components[1] ); |
| 306 | + $tif->template_name = $template_name; |
| 307 | + $query_template_name = str_replace( ' ', '_', $template_name ); |
| 308 | + // also replace periods with underlines, since that's what |
| 309 | + // POST does to strings anyway |
| 310 | + $query_template_name = str_replace( '.', '_', $query_template_name ); |
| 311 | + $chooser_name = false; |
| 312 | + $chooser_caption = false; |
| 313 | + // cycle through the other components |
| 314 | + for ( $i = 2; $i < count( $tag_components ); $i++ ) { |
| 315 | + $component = $tag_components[$i]; |
| 316 | + if ( $component == 'multiple' ) $allow_multiple = true; |
| 317 | + if ( $component == 'strict' ) $strict_parsing = true; |
| 318 | + $sub_components = explode( '=', $component, 2 ); |
| 319 | + if ( count( $sub_components ) == 2 ) { |
| 320 | + if ( $sub_components[0] == 'label' ) { |
| 321 | + $template_label = $sub_components[1]; |
| 322 | + } elseif ( $sub_components[0] == 'chooser' ) { |
| 323 | + $allow_multiple = true; |
| 324 | + $chooser_name = $sub_components[1]; |
| 325 | + } elseif ( $sub_components[0] == 'chooser caption' ) { |
| 326 | + $chooser_caption = $sub_components[1]; |
| 327 | + } |
| 328 | + } |
| 329 | + } |
| 330 | + // if this is the first instance, add the label in the form |
| 331 | + if ( ( $old_template_name != $template_name ) && isset( $template_label ) ) { |
| 332 | + // add a placeholder to the form text so the fieldset can be |
| 333 | + // hidden if chooser support demands it |
| 334 | + if ( $chooser_name !== false ) |
| 335 | + $form_text .= "<fieldset [[placeholder]] haschooser=true>\n"; |
| 336 | + else |
| 337 | + $form_text .= "<fieldset>\n"; |
| 338 | + $form_text .= "<legend>$template_label</legend>\n"; |
| 339 | + } |
| 340 | + $template_text .= "{{" . $tif->template_name; |
| 341 | + $all_fields = $tif->getAllFields(); |
| 342 | + // remove template tag |
| 343 | + $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
| 344 | + $template_instance_query_values = $wgRequest->getArray( $query_template_name ); |
| 345 | + // if we are editing a page, and this template can be found more than |
| 346 | + // once in that page, and multiple values are allowed, repeat this |
| 347 | + // section |
| 348 | + $existing_template_text = null; |
| 349 | + if ( $source_is_page || $form_is_partial ) { |
| 350 | + // replace underlines with spaces in template name, to allow for |
| 351 | + // searching on either |
| 352 | + $search_template_str = str_replace( '_', ' ', $tif->template_name ); |
| 353 | + $preg_match_template_str = str_replace( |
| 354 | + array( '/', '(', ')' ), |
| 355 | + array( '\/', '\(', '\)' ), |
| 356 | + $search_template_str ); |
| 357 | + $found_instance = preg_match( '/{{' . $preg_match_template_str . '\s*[\|}]/i', str_replace( '_', ' ', $existing_page_content ) ); |
| 358 | + if ( $allow_multiple ) { |
| 359 | + // find instances of this template in the page - |
| 360 | + // if there's at least one, re-parse this section of the |
| 361 | + // definition form for the subsequent template instances in |
| 362 | + // this page; if there's none, don't include fields at all. |
| 363 | + // there has to be a more efficient way to handle multiple |
| 364 | + // instances of templates, one that doesn't involve re-parsing |
| 365 | + // the same tags, but I don't know what it is. |
| 366 | + if ( $found_instance ) { |
| 367 | + $instance_num++; |
| 368 | + } else { |
| 369 | + $all_instances_printed = true; |
| 370 | + } |
| 371 | + } |
| 372 | + // get the first instance of this template on the page being edited, |
| 373 | + // even if there are more |
| 374 | + if ( $found_instance && ( $start_char = stripos( str_replace( '_', ' ', $existing_page_content ), '{{' . $search_template_str ) ) !== false ) { |
| 375 | + $fields_start_char = $start_char + 2 + strlen( $search_template_str ); |
| 376 | + // skip ahead to the first real character |
| 377 | + while ( in_array( $existing_page_content[$fields_start_char], array( ' ', '\n', '|' ) ) ) { |
| 378 | + $fields_start_char++; |
| 379 | + } |
| 380 | + $template_contents = array( '0' => '' ); |
| 381 | + // cycle through template call, splitting it up by pipes ('|'), |
| 382 | + // except when that pipe is part of a piped link |
| 383 | + $field = ""; |
| 384 | + $uncompleted_square_brackets = 0; |
| 385 | + $uncompleted_curly_brackets = 2; |
| 386 | + $template_ended = false; |
| 387 | + for ( $i = $fields_start_char; ! $template_ended && ( $i < strlen( $existing_page_content ) ); $i++ ) { |
| 388 | + $c = $existing_page_content[$i]; |
| 389 | + if ( $c == '[' ) { |
| 390 | + $uncompleted_square_brackets++; |
| 391 | + } elseif ( $c == ']' && $uncompleted_square_brackets > 0 ) { |
| 392 | + $uncompleted_square_brackets--; |
| 393 | + } elseif ( $c == '{' ) { |
| 394 | + $uncompleted_curly_brackets++; |
| 395 | + } elseif ( $c == '}' && $uncompleted_curly_brackets > 0 ) { |
| 396 | + $uncompleted_curly_brackets--; |
| 397 | + } |
| 398 | + // handle an end to a field and/or template declaration |
| 399 | + $template_ended = ( $uncompleted_curly_brackets == 0 && $uncompleted_square_brackets == 0 ); |
| 400 | + $field_ended = ( $c == '|' && $uncompleted_square_brackets == 0 && $uncompleted_curly_brackets <= 2 ); |
| 401 | + if ( $template_ended || $field_ended ) { |
| 402 | + // if this was the last character in the template, remove |
| 403 | + // the closing curly brackets |
| 404 | + if ( $template_ended ) { |
| 405 | + $field = substr( $field, 0, - 1 ); |
| 406 | + } |
| 407 | + // either there's an equals sign near the beginning or not - |
| 408 | + // handling is similar in either way; if there's no equals |
| 409 | + // sign, the index of this field becomes the key |
| 410 | + $sub_fields = explode( '=', $field, 2 ); |
| 411 | + if ( count( $sub_fields ) > 1 ) { |
| 412 | + $template_contents[trim( $sub_fields[0] )] = trim( $sub_fields[1] ); |
| 413 | + } else { |
| 414 | + $template_contents[] = trim( $sub_fields[0] ); |
| 415 | + } |
| 416 | + $field = ''; |
| 417 | + } else { |
| 418 | + $field .= $c; |
| 419 | + } |
| 420 | + } |
| 421 | + $existing_template_text = substr( $existing_page_content, $start_char, $i - $start_char ); |
| 422 | + // now remove this template from the text being edited |
| 423 | + // if this is a partial form, establish a new insertion point |
| 424 | + if ( $existing_page_content && $form_is_partial && $wgRequest->getCheck( 'partial' ) ) { |
| 425 | + // if something already exists, set the new insertion point |
| 426 | + // to its position; otherwise just let it lie |
| 427 | + if ( strpos( $existing_page_content, $existing_template_text ) !== false ) { |
| 428 | + $existing_page_content = str_replace( '{{{insertionpoint}}}', '', $existing_page_content ); |
| 429 | + $existing_page_content = str_replace( $existing_template_text, '{{{insertionpoint}}}', $existing_page_content ); |
| 430 | + } |
| 431 | + } else { |
| 432 | + $existing_page_content = str_replace( $existing_template_text, '', $existing_page_content ); |
| 433 | + } |
| 434 | + // if this is not a multiple-instance template, and we've found |
| 435 | + // a match in the source page, there's a good chance that this |
| 436 | + // page was created with this form - note that, so we don't |
| 437 | + // send the user a warning |
| 438 | + // (multiple-instance templates have a greater chance of |
| 439 | + // getting repeated from one form to the next) |
| 440 | + // - on second thought, allow even the presence of multiple- |
| 441 | + // instance templates to validate that this is the correct |
| 442 | + // form: the problem is that some forms contain *only* mutliple- |
| 443 | + // instance templates |
| 444 | + // if (! $allow_multiple) { |
| 445 | + $source_page_matches_this_form = true; |
| 446 | + // } |
| 447 | + } |
| 448 | + } |
| 449 | + // if the input is from the form (meaning the user has hit one |
| 450 | + // of the bottom row of buttons), and we're dealing with a |
| 451 | + // multiple template, get the values for this instance of this |
| 452 | + // template, then delete them from the array, so we can get the |
| 453 | + // next group next time - the next() command for arrays doesn't |
| 454 | + // seem to work here |
| 455 | + if ( ( ! $source_is_page ) && $allow_multiple && $wgRequest ) { |
| 456 | + $all_instances_printed = true; |
| 457 | + if ( $old_template_name != $template_name ) { |
| 458 | + $all_values_for_template = $wgRequest->getArray( $query_template_name ); |
| 459 | + } |
| 460 | + if ( $all_values_for_template ) { |
| 461 | + $cur_key = key( $all_values_for_template ); |
| 462 | + // skip the input coming in from the "starter" div |
| 463 | + if ( $cur_key == 'num' ) { |
| 464 | + unset( $all_values_for_template[$cur_key] ); |
| 465 | + $cur_key = key( $all_values_for_template ); |
| 466 | + } |
| 467 | + if ( $template_instance_query_values = current( $all_values_for_template ) ) { |
| 468 | + $all_instances_printed = false; |
| 469 | + unset( $all_values_for_template[$cur_key] ); |
| 470 | + } |
| 471 | + } |
| 472 | + } |
| 473 | + // ===================================================== |
| 474 | + // end template processing |
| 475 | + // ===================================================== |
| 476 | + } elseif ( $tag_title == 'end template' ) { |
| 477 | + if ( $source_is_page ) { |
| 478 | + // add any unhandled template fields in the page as hidden variables |
| 479 | + if ( isset( $template_contents ) ) |
| 480 | + $form_text .= SFFormUtils::unhandledFieldsHTML( $template_contents ); |
| 481 | + } |
| 482 | + // remove this tag, reset some variables, and close off form HTML tag |
| 483 | + $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
| 484 | + $template_name = null; |
| 485 | + if ( isset( $template_label ) ) { |
| 486 | + $form_text .= "</fieldset>\n"; |
| 487 | + unset ( $template_label ); |
| 488 | + } |
| 489 | + $allow_multiple = false; |
| 490 | + $all_instances_printed = false; |
| 491 | + $instance_num = 0; |
| 492 | + // if the hiding placeholder is still around, this fieldset should |
| 493 | + // be hidden because it is empty and choosers are being used. So, |
| 494 | + // hide it. |
| 495 | + $form_text = str_replace( "[[placeholder]]", "style='display:none'", $form_text ); |
| 496 | + // ===================================================== |
| 497 | + // field processing |
| 498 | + // ===================================================== |
| 499 | + } elseif ( $tag_title == 'field' ) { |
| 500 | + $field_name = trim( $tag_components[1] ); |
| 501 | + // cycle through the other components |
| 502 | + $is_mandatory = false; |
| 503 | + $is_hidden = false; |
| 504 | + $is_restricted = false; |
| 505 | + $is_uploadable = false; |
| 506 | + $is_list = false; |
| 507 | + $input_type = null; |
| 508 | + $field_args = array(); |
| 509 | + $show_on_select = array(); |
| 510 | + $default_value = ""; |
| 511 | + $possible_values = null; |
| 512 | + $semantic_property = null; |
| 513 | + $preload_page = null; |
| 514 | + for ( $i = 2; $i < count( $tag_components ); $i++ ) { |
| 515 | + $component = trim( $tag_components[$i] ); |
| 516 | + if ( $component == 'mandatory' ) { |
| 517 | + $is_mandatory = true; |
| 518 | + } elseif ( $component == 'hidden' ) { |
| 519 | + $is_hidden = true; |
| 520 | + } elseif ( $component == 'restricted' ) { |
| 521 | + $is_restricted = true; |
| 522 | + } elseif ( $component == 'uploadable' ) { |
| 523 | + $field_args['is_uploadable'] = true; |
| 524 | + } elseif ( $component == 'list' ) { |
| 525 | + $is_list = true; |
| 526 | + } elseif ( $component == 'autocomplete' ) { |
| 527 | + $field_args['autocomplete'] = true; |
| 528 | + } elseif ( $component == 'no autocomplete' ) { |
| 529 | + $field_args['no autocomplete'] = true; |
| 530 | + } elseif ( $component == 'remote autocompletion' ) { |
| 531 | + $field_args['remote autocompletion'] = true; |
| 532 | + } elseif ( $component == 'edittools' ) { // free text only |
| 533 | + $free_text_components[] = 'edittools'; |
| 534 | + } else { |
| 535 | + $sub_components = explode( '=', $component, 2 ); |
| 536 | + if ( count( $sub_components ) == 1 ) { |
| 537 | + // add handling for single-value params, for custom input types |
| 538 | + $field_args[$sub_components[0]] = null; |
| 539 | + } elseif ( count( $sub_components ) == 2 ) { |
| 540 | + if ( $sub_components[0] == 'input type' ) { |
| 541 | + $input_type = $sub_components[1]; |
| 542 | + } elseif ( $sub_components[0] == 'default' ) { |
| 543 | + $default_value = $sub_components[1]; |
| 544 | + } elseif ( $sub_components[0] == 'preload' ) { |
| 545 | + // free text field has special handling |
| 546 | + if ( $field_name == 'free text' || $field_name = '<freetext>' ) { |
| 547 | + $free_text_preload_page = $sub_components[1]; |
| 548 | + } else { |
| 549 | + // this variable is not used |
| 550 | + $preload_page = $sub_components[1]; |
| 551 | + } |
| 552 | + } elseif ( $sub_components[0] == 'show on select' ) { |
| 553 | + // html_entity_decode() is needed to turn '>' to '>' |
| 554 | + $vals = explode( ';', html_entity_decode( $sub_components[1] ) ); |
| 555 | + foreach ( $vals as $val ) { |
| 556 | + $option_div_pair = explode( '=>', $val, 2 ); |
| 557 | + if ( count( $option_div_pair ) > 1 ) { |
| 558 | + $option = $option_div_pair[0]; |
| 559 | + $div_id = $option_div_pair[1]; |
| 560 | + if ( array_key_exists( $div_id, $show_on_select ) ) |
| 561 | + $show_on_select[$div_id][] = $option; |
| 562 | + else |
| 563 | + $show_on_select[$div_id] = array( $option ); |
| 564 | + } else { |
| 565 | + $show_on_select[$val] = array(); |
| 566 | + } |
| 567 | + } |
| 568 | + } elseif ( $sub_components[0] == 'autocomplete on property' ) { |
| 569 | + // HACK - we need to figure out if this property is a |
| 570 | + // relation or attribute, i.e. whether it points to wiki |
| 571 | + // pages or not; so construct an SFTemplateField object |
| 572 | + // with this property, and determine it that way |
| 573 | + $property_name = $sub_components[1]; |
| 574 | + $dummy_field = new SFTemplateField(); |
| 575 | + $dummy_field->setSemanticProperty( $property_name ); |
| 576 | + if ( $dummy_field->propertyIsOfType( '_wpg' ) ) |
| 577 | + $field_args['autocomplete field type'] = 'relation'; |
| 578 | + else |
| 579 | + $field_args['autocomplete field type'] = 'attribute'; |
| 580 | + $field_args['autocompletion source'] = $sub_components[1]; |
| 581 | + } elseif ( $sub_components[0] == 'autocomplete on' ) { // for backwards-compatibility |
| 582 | + $field_args['autocomplete field type'] = 'category'; |
| 583 | + $field_args['autocompletion source'] = $sub_components[1]; |
| 584 | + } elseif ( $sub_components[0] == 'autocomplete on category' ) { |
| 585 | + $field_args['autocomplete field type'] = 'category'; |
| 586 | + $field_args['autocompletion source'] = $sub_components[1]; |
| 587 | + } elseif ( $sub_components[0] == 'autocomplete on concept' ) { |
| 588 | + $field_args['autocomplete field type'] = 'concept'; |
| 589 | + $field_args['autocompletion source'] = $sub_components[1]; |
| 590 | + } elseif ( $sub_components[0] == 'autocomplete on namespace' ) { |
| 591 | + $field_args['autocomplete field type'] = 'namespace'; |
| 592 | + $autocompletion_source = $sub_components[1]; |
| 593 | + // special handling for "main" (blank) namespace |
| 594 | + if ( $autocompletion_source == "" ) |
| 595 | + $autocompletion_source = "main"; |
| 596 | + $field_args['autocompletion source'] = $autocompletion_source; |
| 597 | + } elseif ( $sub_components[0] == 'autocomplete from url' ) { |
| 598 | + $field_args['autocomplete field type'] = 'external_url'; |
| 599 | + $field_args['autocompletion source'] = $sub_components[1]; |
| 600 | + // 'external' autocompletion is always done remotely, i.e. via API |
| 601 | + $field_args['remote autocompletion'] = true; |
| 602 | + } elseif ( $sub_components[0] == 'values' ) { |
| 603 | + // remove whitespaces, and un-escape characters |
| 604 | + $possible_values = array_map( 'trim', explode( ',', $sub_components[1] ) ); |
| 605 | + $possible_values = array_map( 'htmlspecialchars_decode', $possible_values ); |
| 606 | + } elseif ( $sub_components[0] == 'values from category' ) { |
| 607 | + $category_name = ucfirst( $sub_components[1] ); |
| 608 | + $possible_values = SFUtils::getAllPagesForCategory( $category_name, 10 ); |
| 609 | + } elseif ( $sub_components[0] == 'values from concept' ) { |
| 610 | + $possible_values = SFUtils::getAllPagesForConcept( $sub_components[1] ); |
| 611 | + } elseif ( $sub_components[0] == 'property' ) { |
| 612 | + $semantic_property = $sub_components[1]; |
| 613 | + } elseif ( $sub_components[0] == 'default filename' ) { |
| 614 | + $default_filename = str_replace( '<page name>', $page_name, $sub_components[1] ); |
| 615 | + $field_args['default filename'] = $default_filename; |
| 616 | + } else { |
| 617 | + $field_args[$sub_components[0]] = $sub_components[1]; |
| 618 | + } |
| 619 | + // for backwards compatibility |
| 620 | + if ( $sub_components[0] == 'autocomplete on' && $sub_components[1] == null ) { |
| 621 | + $field_args['no autocomplete'] = true; |
| 622 | + } |
| 623 | + } |
| 624 | + } |
| 625 | + } // end for |
| 626 | + if ( $allow_multiple ) |
| 627 | + $field_args['part_of_multiple'] = $allow_multiple; |
| 628 | + if ( count( $show_on_select ) > 0 ) |
| 629 | + $field_args['show on select'] = $show_on_select; |
| 630 | + // get the value from the request, if it's there, and if it's not |
| 631 | + // an array |
| 632 | + $escaped_field_name = str_replace( "'", "\'", $field_name ); |
| 633 | + if ( isset( $template_instance_query_values ) && |
| 634 | + $template_instance_query_values != null && |
| 635 | + is_array( $template_instance_query_values ) && |
| 636 | + array_key_exists( $escaped_field_name, $template_instance_query_values ) ) { |
| 637 | + $field_query_val = $template_instance_query_values[$escaped_field_name]; |
| 638 | + if ( $form_submitted || ( $field_query_val != '' && ! is_array( $field_query_val ) ) ) { |
| 639 | + $cur_value = $field_query_val; |
| 640 | + } |
| 641 | + } else |
| 642 | + $cur_value = ''; |
| 643 | + // if ($cur_value && ! is_array($cur_value)) { |
| 644 | + // $cur_value = htmlspecialchars($cur_value); |
| 645 | + // } |
| 646 | + |
| 647 | + if ( $cur_value == null ) { |
| 648 | + // set to default value specified in the form, if it's there |
| 649 | + $cur_value = $default_value; |
| 650 | + } |
| 651 | + |
| 652 | + // if the user is editing a page, and that page contains a call to |
| 653 | + // the template being processed, get the current field's value |
| 654 | + // from the template call |
| 655 | + if ( $source_is_page && ( ! empty( $existing_template_text ) ) ) { |
| 656 | + if ( isset( $template_contents[$field_name] ) ) { |
| 657 | + $cur_value = $template_contents[$field_name]; |
| 658 | + // now remove this value from $template_contents, so that |
| 659 | + // at the end we can have a list of all the fields that |
| 660 | + // weren't handled by the form |
| 661 | + unset( $template_contents[$field_name] ); |
| 662 | + } else { |
| 663 | + $cur_value = ''; |
| 664 | + } |
| 665 | + } |
| 666 | + |
| 667 | + // handle the free text field - if it was declared as |
| 668 | + // "field|free text" (a deprecated usage), it has to be outside |
| 669 | + // of a template |
| 670 | + if ( ( $template_name == '' && $field_name == 'free text' ) || |
| 671 | + $field_name == '<freetext>' ) { |
| 672 | + // add placeholders for the free text in both the form and |
| 673 | + // the page, using <free_text> tags - once all the free text |
| 674 | + // is known (at the end), it will get substituted in |
| 675 | + if ( $is_hidden ) { |
| 676 | + $new_text = SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' ); |
| 677 | + } else { |
| 678 | + if ( ! array_key_exists( 'rows', $field_args ) ) |
| 679 | + $field_args['rows'] = 5; |
| 680 | + if ( ! array_key_exists( 'cols', $field_args ) ) |
| 681 | + $field_args['cols'] = 80; |
| 682 | + $sfgTabIndex++; |
| 683 | + $sfgFieldNum++; |
| 684 | + list( $new_text, $new_javascript_text ) = SFFormInputs::textAreaHTML( '!free_text!', 'free_text', false, ( $form_is_disabled || $is_restricted ), $field_args ); |
| 685 | + if ( in_array( 'edittools', $free_text_components ) ) { |
| 686 | + // borrowed from EditPage::showEditTools() |
| 687 | + $options[] = 'parse'; |
| 688 | + $edittools_text = wfMsgExt( 'edittools', array( 'parse' ), array( 'content' ) ); |
| 689 | + |
| 690 | + $new_text .= <<<END |
| 691 | + <div class="mw-editTools"> |
| 692 | + $edittools_text |
| 693 | + </div> |
| 694 | + |
| 695 | +END; |
| 696 | + } |
| 697 | + $fields_javascript_text .= $new_javascript_text; |
| 698 | + } |
| 699 | + $free_text_was_included = true; |
| 700 | + // add a similar placeholder to the data text |
| 701 | + $data_text .= "!free_text!\n"; |
| 702 | + } |
| 703 | + |
| 704 | + if ( $template_name == '' || $field_name == '<freetext>' ) { |
| 705 | + $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
| 706 | + } else { |
| 707 | + if ( is_array( $cur_value ) ) { |
| 708 | + // first, check if it's a list |
| 709 | + if ( array_key_exists( 'is_list', $cur_value ) && |
| 710 | + $cur_value['is_list'] == true ) { |
| 711 | + $cur_value_in_template = ""; |
| 712 | + if ( array_key_exists( 'delimiter', $field_args ) ) { |
| 713 | + $delimiter = $field_args['delimiter']; |
| 714 | + } else { |
| 715 | + $delimiter = ","; |
| 716 | + } |
| 717 | + foreach ( $cur_value as $key => $val ) { |
| 718 | + if ( $key !== "is_list" ) { |
| 719 | + if ( $cur_value_in_template != "" ) { |
| 720 | + $cur_value_in_template .= $delimiter . " "; |
| 721 | + } |
| 722 | + $cur_value_in_template .= $val; |
| 723 | + } |
| 724 | + } |
| 725 | + } else { |
| 726 | + // otherwise: |
| 727 | + // if it has 1 or 2 elements, assume it's a checkbox; if it has |
| 728 | + // 3 elements, assume it's a date |
| 729 | + // - this handling will have to get more complex if other |
| 730 | + // possibilities get added |
| 731 | + if ( count( $cur_value ) == 1 ) { |
| 732 | + // manually load SMW's message values here, in case they |
| 733 | + // didn't get loaded before |
| 734 | + wfLoadExtensionMessages( 'SemanticMediaWiki' ); |
| 735 | + $words_for_false = explode( ',', wfMsgForContent( 'smw_false_words' ) ); |
| 736 | + // for each language, there's a series of words that are |
| 737 | + // equal to false - get the word in the series that matches |
| 738 | + // "no"; generally, that's the third word |
| 739 | + $index_of_no = 2; |
| 740 | + if ( count( $words_for_false ) > $index_of_no ) { |
| 741 | + $no = ucwords( $words_for_false[$index_of_no] ); |
| 742 | + } elseif ( count( $words_for_false ) == 0 ) { |
| 743 | + $no = "0"; // some safe value if no words are found |
| 744 | + } else { |
| 745 | + $no = ucwords( $words_for_false[0] ); |
| 746 | + } |
| 747 | + $cur_value_in_template = $no; |
| 748 | + } elseif ( count( $cur_value ) == 2 ) { |
| 749 | + wfLoadExtensionMessages( 'SemanticMediaWiki' ); |
| 750 | + $words_for_true = explode( ',', wfMsgForContent( 'smw_true_words' ) ); |
| 751 | + // get the value in the 'true' series that tends to be "yes", |
| 752 | + // and go with that one - generally, that's the third word |
| 753 | + $index_of_yes = 2; |
| 754 | + if ( count( $words_for_true ) > $index_of_yes ) { |
| 755 | + $yes = ucwords( $words_for_true[$index_of_yes] ); |
| 756 | + } elseif ( count( $words_for_true ) == 0 ) { |
| 757 | + $yes = "1"; // some safe value if no words are found |
| 758 | + } else { |
| 759 | + $yes = ucwords( $words_for_true[0] ); |
| 760 | + } |
| 761 | + $cur_value_in_template = $yes; |
| 762 | + // if it's 3 or greater, assume it's a date or datetime |
| 763 | + } elseif ( count( $cur_value ) >= 3 ) { |
| 764 | + $month = $cur_value['month']; |
| 765 | + $day = $cur_value['day']; |
| 766 | + if ( $day != '' ) { |
| 767 | + global $wgAmericanDates; |
| 768 | + if ( $wgAmericanDates == false ) { |
| 769 | + // pad out day to always be two digits |
| 770 | + $day = str_pad( $day, 2, "0", STR_PAD_LEFT ); |
| 771 | + } |
| 772 | + } |
| 773 | + $year = $cur_value['year']; |
| 774 | + $hour = $minute = $second = $ampm24h = $timezone = null; |
| 775 | + if ( isset( $cur_value['hour'] ) ) $hour = $cur_value['hour']; |
| 776 | + if ( isset( $cur_value['minute'] ) ) $minute = $cur_value['minute']; |
| 777 | + if ( isset( $cur_value['second'] ) ) $second = $cur_value['second']; |
| 778 | + if ( isset( $cur_value['ampm24h'] ) ) $ampm24h = $cur_value['ampm24h']; |
| 779 | + if ( isset( $cur_value['timezone'] ) ) $timezone = $cur_value['timezone']; |
| 780 | + if ( $month != '' && $day != '' && $year != '' ) { |
| 781 | + // special handling for American dates - otherwise, just |
| 782 | + // the standard year/month/day (where month is a number) |
| 783 | + global $wgAmericanDates; |
| 784 | + if ( $wgAmericanDates == true ) { |
| 785 | + $cur_value_in_template = "$month $day, $year"; |
| 786 | + } else { |
| 787 | + $cur_value_in_template = "$year/$month/$day"; |
| 788 | + } |
| 789 | + // include whatever time information we have |
| 790 | + if ( ! is_null( $hour ) ) |
| 791 | + $cur_value_in_template .= " " . str_pad( intval( substr( $hour, 0, 2 ) ), 2, '0', STR_PAD_LEFT ) . ":" . str_pad( intval( substr( $minute, 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
| 792 | + if ( ! is_null( $second ) ) |
| 793 | + $cur_value_in_template .= ":" . str_pad( intval( substr( $second, 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
| 794 | + if ( ! is_null( $ampm24h ) ) |
| 795 | + $cur_value_in_template .= " $ampm24h"; |
| 796 | + if ( ! is_null( $timezone ) ) |
| 797 | + $cur_value_in_template .= " $timezone"; |
| 798 | + } else { |
| 799 | + $cur_value_in_template = ""; |
| 800 | + } |
| 801 | + } |
| 802 | + } |
| 803 | + } else { // value is not an array |
| 804 | + $cur_value_in_template = $cur_value; |
| 805 | + } |
| 806 | + if ( $query_template_name == null || $query_template_name == '' ) |
| 807 | + $input_name = $field_name; |
| 808 | + elseif ( $allow_multiple ) |
| 809 | + // 'num' will get replaced by an actual index, either in PHP |
| 810 | + // or in Javascript, later on |
| 811 | + $input_name = $query_template_name . '[num][' . $field_name . ']'; |
| 812 | + else |
| 813 | + $input_name = $query_template_name . '[' . $field_name . ']'; |
| 814 | + |
| 815 | + // if we're creating the page name from a formula based on |
| 816 | + // form values, see if the current input is part of that formula, |
| 817 | + // and if so, substitute in the actual value |
| 818 | + if ( $form_submitted && $generated_page_name != '' ) { |
| 819 | + // this line appears unnecessary |
| 820 | + // $generated_page_name = str_replace('.', '_', $generated_page_name); |
| 821 | + $generated_page_name = str_replace( ' ', '_', $generated_page_name ); |
| 822 | + $escaped_input_name = str_replace( ' ', '_', $input_name ); |
| 823 | + $generated_page_name = str_ireplace( "<$escaped_input_name>", $cur_value_in_template, $generated_page_name ); |
| 824 | + // once the substitution is done, replace underlines back |
| 825 | + // with spaces |
| 826 | + $generated_page_name = str_replace( '_', ' ', $generated_page_name ); |
| 827 | + } |
| 828 | + // disable this field if either the whole form is disabled, or |
| 829 | + // it's a restricted field and user doesn't have sysop privileges |
| 830 | + $is_disabled = ( $form_is_disabled || |
| 831 | + ( $is_restricted && ( ! $wgUser || ! $wgUser->isAllowed( 'editrestrictedfields' ) ) ) ); |
| 832 | + // create an SFFormField instance based on all the |
| 833 | + // parameters in the form definition, and any information from |
| 834 | + // the template definition (contained in the $all_fields parameter) |
| 835 | + $form_field = SFFormField::createFromDefinition( $field_name, $input_name, |
| 836 | + $is_mandatory, $is_hidden, $is_uploadable, $possible_values, $is_disabled, |
| 837 | + $is_list, $input_type, $field_args, $all_fields, $strict_parsing ); |
| 838 | + // if a property was set in the form definition, overwrite whatever |
| 839 | + // is set in the template field - this is somewhat of a hack, since |
| 840 | + // parameters set in the form definition are meant to go into the |
| 841 | + // SFFormField object, not the SFTemplateField object it contains; |
| 842 | + // it seemed like too much work, though, to create an |
| 843 | + // SFFormField::setSemanticProperty() function just for this call |
| 844 | + if ( $semantic_property != null ) |
| 845 | + $form_field->template_field->setSemanticProperty( $semantic_property ); |
| 846 | + |
| 847 | + // call hooks - unfortunately this has to be split into two |
| 848 | + // separate calls, because of the different variable names in |
| 849 | + // each case |
| 850 | + if ( $form_submitted ) |
| 851 | + wfRunHooks( 'sfCreateFormField', array( &$form_field, &$cur_value_in_template, true ) ); |
| 852 | + else |
| 853 | + wfRunHooks( 'sfCreateFormField', array( &$form_field, &$cur_value, false ) ); |
| 854 | + // if this is not part of a 'multiple' template, increment the |
| 855 | + // global tab index (used for correct tabbing) |
| 856 | + if ( ! array_key_exists( 'part_of_multiple', $field_args ) ) |
| 857 | + $sfgTabIndex++; |
| 858 | + // increment the global field number regardless |
| 859 | + $sfgFieldNum++; |
| 860 | + // if the field is a date field, and its default value was set |
| 861 | + // to 'now', and it has no current value, set $cur_value to be |
| 862 | + // the current date |
| 863 | + if ( $default_value == 'now' && |
| 864 | + // if the date is hidden, cur_value will already be set |
| 865 | + // to the default value |
| 866 | + ( $cur_value == '' || $cur_value == 'now' ) ) { |
| 867 | + if ( $input_type == 'date' || $input_type == 'datetime' || |
| 868 | + $input_type == 'datetime with timezone' || $input_type == 'year' || |
| 869 | + ( $input_type == '' && $form_field->template_field->propertyIsOfType( '_dat' ) ) ) { |
| 870 | + // get current time, for the time zone specified in the wiki |
| 871 | + global $wgLocaltimezone; |
| 872 | + putenv( 'TZ=' . $wgLocaltimezone ); |
| 873 | + $cur_time = time(); |
| 874 | + $year = date( "Y", $cur_time ); |
| 875 | + $month = date( "n", $cur_time ); |
| 876 | + $day = date( "j", $cur_time ); |
| 877 | + global $wgAmericanDates, $sfg24HourTime; |
| 878 | + if ( $wgAmericanDates == true ) { |
| 879 | + $month_names = SFFormUtils::getMonthNames(); |
| 880 | + $month_name = $month_names[$month - 1]; |
| 881 | + $cur_value_in_template = "$month_name $day, $year"; |
| 882 | + } else { |
| 883 | + $cur_value_in_template = "$year/$month/$day"; |
| 884 | + } |
| 885 | + if ( $input_type == 'datetime' || $input_type == 'datetime with timezone' ) { |
| 886 | + if ( $sfg24HourTime ) { |
| 887 | + $hour = str_pad( intval( substr( date( "G", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
| 888 | + } else { |
| 889 | + $hour = str_pad( intval( substr( date( "g", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
| 890 | + } |
| 891 | + $minute = str_pad( intval( substr( date( "i", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
| 892 | + $second = str_pad( intval( substr( date( "s", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT ); |
| 893 | + if ( $sfg24HourTime ) { |
| 894 | + $cur_value_in_template .= " $hour:$minute:$second"; |
| 895 | + } else { |
| 896 | + $ampm = date( "A", $cur_time ); |
| 897 | + $cur_value_in_template .= " $hour:$minute:$second $ampm"; |
| 898 | + } |
| 899 | + } |
| 900 | + if ( $input_type == 'datetime with timezone' ) { |
| 901 | + $timezone = date( "T", $cur_time ); |
| 902 | + $cur_value_in_template .= " $timezone"; |
| 903 | + } |
| 904 | + } |
| 905 | + } |
| 906 | + // if the field is a text field, and its default value was set |
| 907 | + // to 'current user', and it has no current value, set $cur_value |
| 908 | + // to be the current user |
| 909 | + if ( $default_value == 'current user' && |
| 910 | + // if the date is hidden, cur_value will already be set |
| 911 | + // to the default value |
| 912 | + ( $cur_value == '' || $cur_value == 'current user' ) ) { |
| 913 | + if ( $input_type == 'text' || $input_type == '' ) { |
| 914 | + $cur_value_in_template = $wgUser->getName(); |
| 915 | + $cur_value = $cur_value_in_template; |
| 916 | + } |
| 917 | + } |
| 918 | + list( $new_text, $new_javascript_text ) = $this->formFieldHTML( $form_field, $cur_value ); |
| 919 | + |
| 920 | + $fields_javascript_text .= $new_javascript_text; |
| 921 | + |
| 922 | + // if this field is disabled, add a hidden field holding |
| 923 | + // the value of this field, because disabled inputs for some |
| 924 | + // reason don't submit their value |
| 925 | + if ( $form_field->is_disabled ) { |
| 926 | + if ( $field_name == 'free text' || $field_name == '<freetext>' ) { |
| 927 | + $new_text .= SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' ); |
| 928 | + } else { |
| 929 | + $new_text .= SFFormUtils::hiddenFieldHTML( $input_name, $cur_value ); |
| 930 | + } |
| 931 | + } |
| 932 | + |
| 933 | + if ( $new_text ) { |
| 934 | + // include the field name only for non-numeric field names |
| 935 | + if ( is_numeric( $field_name ) ) { |
| 936 | + $template_text .= "|$cur_value_in_template"; |
| 937 | + } else { |
| 938 | + // if the value is null, don't include it at all |
| 939 | + if ( $cur_value_in_template != '' ) |
| 940 | + $template_text .= "\n|$field_name=$cur_value_in_template"; |
| 941 | + } |
| 942 | + $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
| 943 | + // also add to Javascript validation code |
| 944 | + $input_id = "input_" . $sfgFieldNum; |
| 945 | + $info_id = "info_" . $sfgFieldNum; |
| 946 | + if ( $is_mandatory ) { |
| 947 | + if ( $input_type == 'date' || $input_type == 'datetime' || $input_type == 'datetime with timezone' || |
| 948 | + ( $input_type == '' && $form_field->template_field->propertyIsOfType( '_dat' ) ) ) { |
| 949 | + $sfgJSValidationCalls[] = "validate_mandatory_field ('$input_id" . "_month', '$info_id')"; |
| 950 | + $sfgJSValidationCalls[] = "validate_mandatory_field ('$input_id" . "_day', '$info_id')"; |
| 951 | + $sfgJSValidationCalls[] = "validate_mandatory_field ('$input_id" . "_year', '$info_id')"; |
| 952 | + if ( $input_type == 'datetime' || $input_type == 'datetime with timezone' ) { |
| 953 | + // TODO - validate the time fields |
| 954 | + if ( $input_type == 'datetime with timezone' ) { |
| 955 | + // TODO - validate the timezone |
| 956 | + } |
| 957 | + } |
| 958 | + } else { |
| 959 | + if ( $allow_multiple ) { |
| 960 | + if ( $all_instances_printed ) { |
| 961 | + $sfgJSValidationCalls[] = "validate_multiple_mandatory_fields($sfgFieldNum)"; |
| 962 | + } else { |
| 963 | + $sfgJSValidationCalls[] = "validate_mandatory_field(\"input_$sfgFieldNum\", \"info_$sfgFieldNum\")"; |
| 964 | + } |
| 965 | + } elseif ( $input_type == 'radiobutton' || $input_type == 'category' ) { |
| 966 | + // only add this if there's a "None" option |
| 967 | + if ( empty( $default_value ) ) { |
| 968 | + $sfgJSValidationCalls[] = "validate_mandatory_radiobutton('$input_id', '$info_id')"; |
| 969 | + } |
| 970 | + } elseif ( ( $form_field->template_field->is_list && $form_field->template_field->field_type == 'enumeration' && $input_type != 'listbox' ) || ( $input_type == 'checkboxes' ) ) { |
| 971 | + $sfgJSValidationCalls[] = "validate_mandatory_checkboxes('$input_id', '$info_id')"; |
| 972 | + } else { |
| 973 | + $sfgJSValidationCalls[] = "validate_mandatory_field('$input_id', '$info_id')"; |
| 974 | + } |
| 975 | + } |
| 976 | + } |
| 977 | + } else { |
| 978 | + $start_position = $brackets_end_loc; |
| 979 | + } |
| 980 | + } |
| 981 | + // ===================================================== |
| 982 | + // standard input processing |
| 983 | + // ===================================================== |
| 984 | + } elseif ( $tag_title == 'standard input' ) { |
| 985 | + // handle all the possible values |
| 986 | + $input_name = $tag_components[1]; |
| 987 | + $input_label = null; |
| 988 | + $attr = array(); |
| 989 | + |
| 990 | + // if it's a query, ignore all standard inputs except run query |
| 991 | + if ( ( $is_query && $input_name != 'run query' ) || ( !$is_query && $input_name == 'run query' ) ) { |
| 992 | + $new_text = ""; |
| 993 | + $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
| 994 | + continue; |
| 995 | + } |
| 996 | + // set a flag so that the standard 'form bottom' won't get displayed |
| 997 | + $this->standardInputsIncluded = true; |
| 998 | + // cycle through the other components |
| 999 | + for ( $i = 2; $i < count( $tag_components ); $i++ ) { |
| 1000 | + $component = $tag_components[$i]; |
| 1001 | + $sub_components = explode( '=', $component ); |
| 1002 | + if ( count( $sub_components ) == 1 ) { |
| 1003 | + if ( $sub_components[0] == 'edittools' ) { |
| 1004 | + $free_text_components[] = 'edittools'; |
| 1005 | + } |
| 1006 | + } elseif ( count( $sub_components ) == 2 ) { |
| 1007 | + switch( $sub_components[0] ) { |
| 1008 | + case 'label': |
| 1009 | + $input_label = $sub_components[1]; |
| 1010 | + break; |
| 1011 | + case 'class': |
| 1012 | + case 'style': |
| 1013 | + $attr[$sub_components[0]] = $sub_components[1]; |
| 1014 | + break; |
| 1015 | + } |
| 1016 | + // free text input needs more handling than the rest |
| 1017 | + if ( $input_name == 'free text' || $input_name == '<freetext>' ) { |
| 1018 | + if ( $sub_components[0] == 'preload' ) { |
| 1019 | + $free_text_preload_page = $sub_components[1]; |
| 1020 | + } |
| 1021 | + } |
| 1022 | + } |
| 1023 | + } |
| 1024 | + if ( $input_name == 'summary' ) { |
| 1025 | + $new_text = SFFormUtils::summaryInputHTML( $form_is_disabled, $input_label, $attr ); |
| 1026 | + } elseif ( $input_name == 'minor edit' ) { |
| 1027 | + $new_text = SFFormUtils::minorEditInputHTML( $form_is_disabled, $input_label, $attr ); |
| 1028 | + } elseif ( $input_name == 'watch' ) { |
| 1029 | + $new_text = SFFormUtils::watchInputHTML( $form_is_disabled, $input_label, $attr ); |
| 1030 | + } elseif ( $input_name == 'save' ) { |
| 1031 | + $new_text = SFFormUtils::saveButtonHTML( $form_is_disabled, $input_label, $attr ); |
| 1032 | + } elseif ( $input_name == 'preview' ) { |
| 1033 | + $new_text = SFFormUtils::showPreviewButtonHTML( $form_is_disabled, $input_label, $attr ); |
| 1034 | + } elseif ( $input_name == 'changes' ) { |
| 1035 | + $new_text = SFFormUtils::showChangesButtonHTML( $form_is_disabled, $input_label, $attr ); |
| 1036 | + } elseif ( $input_name == 'cancel' ) { |
| 1037 | + $new_text = SFFormUtils::cancelLinkHTML( $form_is_disabled, $input_label, $attr ); |
| 1038 | + } elseif ( $input_name == 'run query' ) { |
| 1039 | + $new_text = SFFormUtils::runQueryButtonHTML( $form_is_disabled, $input_label, $attr ); |
| 1040 | + } |
| 1041 | + $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
| 1042 | + // ===================================================== |
| 1043 | + // page info processing |
| 1044 | + // ===================================================== |
| 1045 | + } elseif ( $tag_title == 'info' ) { |
| 1046 | + // TODO: Generate an error message if this is included more than once |
| 1047 | + foreach ( array_slice( $tag_components, 1 ) as $component ) { |
| 1048 | + $sub_components = explode( '=', $component, 2 ); |
| 1049 | + $tag = $sub_components[0]; |
| 1050 | + if ( $tag == 'create title' || $tag == 'add title' ) { |
| 1051 | + // handle this only if we're adding a page |
| 1052 | + if ( ! $this->mPageTitle->exists() ) { |
| 1053 | + $val = $sub_components[1]; |
| 1054 | + $form_page_title = $val; |
| 1055 | + } |
| 1056 | + } |
| 1057 | + elseif ( $tag == 'edit title' ) { |
| 1058 | + // handle this only if we're editing a page |
| 1059 | + if ( $this->mPageTitle->exists() ) { |
| 1060 | + $val = $sub_components[1]; |
| 1061 | + $form_page_title = $val; |
| 1062 | + } |
| 1063 | + } |
| 1064 | + elseif ( $tag == 'partial form' ) { |
| 1065 | + $form_is_partial = true; |
| 1066 | + // replacement pages may have minimal matches... |
| 1067 | + $source_page_matches_this_form = true; |
| 1068 | + } |
| 1069 | + elseif ( $tag == 'includeonly free text' || $tag == 'onlyinclude free text' ) { |
| 1070 | + $onlyinclude_free_text = true; |
| 1071 | + } |
| 1072 | + } |
| 1073 | + $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); |
| 1074 | + // ===================================================== |
| 1075 | + // default outer level processing |
| 1076 | + // ===================================================== |
| 1077 | + } else { // tag is not one of the three allowed values |
| 1078 | + // ignore tag |
| 1079 | + $start_position = $brackets_end_loc; |
| 1080 | + } // end if |
| 1081 | + } // end while |
| 1082 | + |
| 1083 | + if ( ! $all_instances_printed ) { |
| 1084 | + if ( $template_text != '' ) { |
| 1085 | + // for mostly aesthetic purposes, if the template call ends with |
| 1086 | + // a bunch of pipes (i.e., it's an indexed template with unused |
| 1087 | + // parameters at the end), remove the pipes |
| 1088 | + $template_text = preg_replace( '/\|*$/', '', $template_text ); |
| 1089 | + // add another newline before the final bracket, if this template |
| 1090 | + // call is already more than one line |
| 1091 | + if ( strpos( $template_text, "\n" ) ) |
| 1092 | + $template_text .= "\n"; |
| 1093 | + // if we're editing an existing page, and there were fields in |
| 1094 | + // the template call not handled by this form, preserve those |
| 1095 | + $template_text .= SFFormUtils::addUnhandledFields(); |
| 1096 | + $template_text .= "}}"; |
| 1097 | + $data_text .= $template_text . "\n"; |
| 1098 | + // if there is a placeholder in the text, we know that we are |
| 1099 | + // doing a replace |
| 1100 | + if ( $existing_page_content && strpos( $existing_page_content, '{{{insertionpoint}}}', 0 ) !== false ) { |
| 1101 | + $existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}(\r?\n?)/', |
| 1102 | + preg_replace( '/\}\}/m', '}�', |
| 1103 | + preg_replace( '/\{\{/m', '�{', $template_text ) ) . |
| 1104 | + "\n{{{insertionpoint}}}", |
| 1105 | + $existing_page_content ); |
| 1106 | + // otherwise, if it's a partial form, we have to add the new |
| 1107 | + // text somewhere |
| 1108 | + } elseif ( $form_is_partial && $wgRequest->getCheck( 'partial' ) ) { |
| 1109 | + $existing_page_content = preg_replace( '/\}\}/m', '}�', |
| 1110 | + preg_replace( '/\{\{/m', '�{', $template_text ) ) . |
| 1111 | + "\n{{{insertionpoint}}}\n" . $existing_page_content; |
| 1112 | + } |
| 1113 | + } |
| 1114 | + } |
| 1115 | + |
| 1116 | + if ( $allow_multiple ) { |
| 1117 | + if ( ! $all_instances_printed ) { |
| 1118 | + // add the character "a" onto the instance number of this input |
| 1119 | + // in the form, to differentiate the inputs the form starts out |
| 1120 | + // with from any inputs added by the Javascript |
| 1121 | + $section = str_replace( '[num]', "[{$instance_num}a]", $section ); |
| 1122 | + $remove_text = wfMsg( 'sf_formedit_remove' ); |
| 1123 | + $form_text .= <<<END |
| 1124 | + <div id="wrapper_$sfgFieldNum" class="multipleTemplate"> |
| 1125 | + $section |
| 1126 | + <input type="button" onclick="removeInstance('wrapper_$sfgFieldNum');" value="$remove_text" tabindex="$sfgTabIndex" class="remove" /> |
| 1127 | + </div> |
| 1128 | + |
| 1129 | +END; |
| 1130 | + // this will cause the section to be re-parsed on the next go |
| 1131 | + $section_num--; |
| 1132 | + // because there is an instance, the fieldset will never be hidden, |
| 1133 | + // even if choosers are being used. So, do not hide the fieldset. |
| 1134 | + $form_text = str_replace( "[[placeholder]]", "", $form_text ); |
| 1135 | + } else { |
| 1136 | + // this is the last instance of this template - stick an 'add' |
| 1137 | + // button in the form |
| 1138 | + $form_text .= <<<END |
| 1139 | + <div id="starter_$query_template_name" class="multipleTemplate" style="display: none;"> |
| 1140 | + $section |
| 1141 | + </div> |
| 1142 | + <div id="main_$query_template_name"></div> |
| 1143 | + |
| 1144 | +END; |
| 1145 | + $add_another = wfMsg( 'sf_formedit_addanother' ); |
| 1146 | + $form_text .= <<<END |
| 1147 | + <p style="margin-left:10px;"> |
| 1148 | + <p><input type="button" onclick="addInstance('starter_$query_template_name', 'main_$query_template_name', '$sfgFieldNum');" value="$add_another" tabindex="$sfgTabIndex" class="addAnother" /></p> |
| 1149 | + |
| 1150 | +END; |
| 1151 | + // if a chooser is being used for this template, add the template |
| 1152 | + // to the chooser data array |
| 1153 | + if ( $chooser_name !== false ) |
| 1154 | + $choosers[$chooser_name][] = array( $query_template_name, $sfgFieldNum, $chooser_caption ); |
| 1155 | + } |
| 1156 | + } else { |
| 1157 | + $form_text .= $section; |
| 1158 | + } |
| 1159 | + |
| 1160 | + } // end for |
| 1161 | + |
| 1162 | + // if it wasn't included in the form definition, add the |
| 1163 | + // 'free text' input as a hidden field at the bottom |
| 1164 | + if ( ! $free_text_was_included ) { |
| 1165 | + $form_text .= SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' ); |
| 1166 | + } |
| 1167 | + // get free text, and add to page data, as well as retroactively |
| 1168 | + // inserting it into the form |
| 1169 | + |
| 1170 | + // If $form_is_partial is true then either: |
| 1171 | + // (a) we're processing a replacement (param 'partial' == 1) |
| 1172 | + // (b) we're sending out something to be replaced (param 'partial' is missing) |
| 1173 | + if ( $form_is_partial ) { |
| 1174 | + if ( !$wgRequest->getCheck( 'partial' ) ) { |
| 1175 | + $free_text = $original_page_content; |
| 1176 | + $form_text .= SFFormUtils::hiddenFieldHTML( 'partial', 1 ); |
| 1177 | + } else { |
| 1178 | + $free_text = null; |
| 1179 | + $existing_page_content = preg_replace( '/�\{(.*?)\}�/s', '{{\1}}', $existing_page_content ); |
| 1180 | + $existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}/', '', $existing_page_content ); |
| 1181 | + } |
| 1182 | + } elseif ( $source_is_page ) { |
| 1183 | + // if the page is the source, free_text will just be whatever in the |
| 1184 | + // page hasn't already been inserted into the form |
| 1185 | + $free_text = trim( $existing_page_content ); |
| 1186 | + // or get it from a form submission |
| 1187 | + } elseif ( $wgRequest->getCheck( 'free_text' ) ) { |
| 1188 | + $free_text = $wgRequest->getVal( 'free_text' ); |
| 1189 | + if ( ! $free_text_was_included ) { |
| 1190 | + $data_text .= "!free_text!"; |
| 1191 | + } |
| 1192 | + // or get it from the form definition |
| 1193 | + } elseif ( $free_text_preload_page != null ) { |
| 1194 | + $free_text = SFFormUtils::getPreloadedText( $free_text_preload_page ); |
| 1195 | + } else { |
| 1196 | + $free_text = null; |
| 1197 | + } |
| 1198 | + if ( $onlyinclude_free_text ) { |
| 1199 | + // modify free text and data text to insert <onlyinclude> tags |
| 1200 | + $free_text = str_replace( "<onlyinclude>", '', $free_text ); |
| 1201 | + $free_text = str_replace( "</onlyinclude>", '', $free_text ); |
| 1202 | + $free_text = trim( $free_text ); |
| 1203 | + $data_text = str_replace( '!free_text!', '<onlyinclude>!free_text!</onlyinclude>', $data_text ); |
| 1204 | + } |
| 1205 | + // if the FCKeditor extension is installed, use that for the free text input |
| 1206 | + global $wgFCKEditorDir; |
| 1207 | + if ( $wgFCKEditorDir ) { |
| 1208 | + $showFCKEditor = SFFormUtils::getShowFCKEditor(); |
| 1209 | + if ( !$form_submitted && ( $showFCKEditor & RTE_VISIBLE ) ) { |
| 1210 | + $free_text = SFFormUtils::prepareTextForFCK( $free_text ); |
| 1211 | + } |
| 1212 | + } else { |
| 1213 | + $showFCKEditor = 0; |
| 1214 | + } |
| 1215 | + // now that we have it, substitute free text into the form and page |
| 1216 | + $escaped_free_text = Sanitizer::safeEncodeAttribute( $free_text ); |
| 1217 | + $form_text = str_replace( '!free_text!', $escaped_free_text, $form_text ); |
| 1218 | + $data_text = str_replace( '!free_text!', $free_text, $data_text ); |
| 1219 | + |
| 1220 | + // add a warning in, if we're editing an existing page and that page |
| 1221 | + // appears to not have been created with this form |
| 1222 | + if ( $this->mPageTitle->exists() && ( $existing_page_content != '' ) && ! $source_page_matches_this_form ) { |
| 1223 | + $form_text = ' <div class="warningMessage">' . wfMsg( 'sf_formedit_formwarning', $this->mPageTitle->getFullURL() ) . "</div>\n" . $form_text; |
| 1224 | + } |
| 1225 | + |
| 1226 | + // Substitute the choosers in here too. |
| 1227 | + $chooser_count = 0; |
| 1228 | + $chooser_text = ""; |
| 1229 | + $using_choosers = "false"; |
| 1230 | + foreach ( $choosers as $choosername => $chooser ) { |
| 1231 | + if ( count( $chooser ) != 0 ) { |
| 1232 | + $chooser_count++; |
| 1233 | + if ( $chooser_count == 1 ) { |
| 1234 | + // emit the initial javascript code |
| 1235 | + $using_choosers = "true"; |
| 1236 | + $chooser_text .= <<<END |
| 1237 | +<script type="text/javascript">/* <![CDATA[ */ |
| 1238 | + |
| 1239 | +function updatechooserbutton(f,n) |
| 1240 | +{ |
| 1241 | + document.getElementById(n).disabled = (f.options[f.selectedIndex].value=="invalid"); |
| 1242 | +} |
| 1243 | + |
| 1244 | +function addInstanceFromChooser(chooserid) |
| 1245 | +{ |
| 1246 | + var chooser = document.getElementById(chooserid); |
| 1247 | + var optionstring = chooser.options[chooser.selectedIndex].value; |
| 1248 | + var pos = optionstring.indexOf(","); |
| 1249 | + var tabindex = optionstring.substr(0,pos); |
| 1250 | + var chooservalue = optionstring.substr(pos+1); |
| 1251 | + addInstance('starter_' + chooservalue, 'main_' + chooservalue, parseInt(tabindex)); |
| 1252 | +} |
| 1253 | + |
| 1254 | +//The fieldset containing the given element was just updated. If the fieldset is associated with a chooser, |
| 1255 | +//ensure that the fieldset is hidden if and only if there are no template instances inside. |
| 1256 | +function hideOrShowFieldset(element) |
| 1257 | +{ |
| 1258 | + //Find fieldset |
| 1259 | + while (element.tagName.toLowerCase() != "fieldset") |
| 1260 | + element = element.parentNode; |
| 1261 | + //Bail out if fieldset is not part of chooser |
| 1262 | + if (!element.getAttribute("haschooser")) |
| 1263 | + return; |
| 1264 | + //Now look for "input" or "select" tags that don't look like they're part of the starter template |
| 1265 | + var inputs = element.getElementsByTagName("input"); |
| 1266 | + var x; |
| 1267 | + var show = false; |
| 1268 | + for (x=0;x<inputs.length;x++) |
| 1269 | + { |
| 1270 | + if (inputs[x].type=="text" && inputs[x].name.indexOf("[num]") == -1) |
| 1271 | + show = true; |
| 1272 | + } |
| 1273 | + var selects = element.getElementsByTagName("select"); |
| 1274 | + for (x=0;x<selects.length;x++) |
| 1275 | + { |
| 1276 | + if (selects[x].name.indexOf("[num]") == -1) |
| 1277 | + show = true; |
| 1278 | + } |
| 1279 | + //Now show or hide fieldset |
| 1280 | + element.style.display = (show?"block":"none"); |
| 1281 | +} |
| 1282 | +/* ]]> */ </script> |
| 1283 | + |
| 1284 | +END; |
| 1285 | + } |
| 1286 | + |
| 1287 | + $chooser_text .= "<p>$choosername:<select id='chooserselect$chooser_count' size='1' onchange='updatechooserbutton(this,\"chooserbutton$chooser_count\")'>\n"; |
| 1288 | + $chooser_text .= "<option value='invalid'>" . wfMsg( 'sf_createform_choosefield' ) . "</option>\n"; |
| 1289 | + foreach ( $chooser as $chooser_item ) { |
| 1290 | + $chooser_value = str_replace( '"', '\\"', $chooser_item[0] ); |
| 1291 | + $tabindex = $chooser_item[1]; |
| 1292 | + $chooser_caption = $chooser_item[2]; |
| 1293 | + if ( $chooser_caption === false ) |
| 1294 | + $chooser_caption = str_replace( '_', ' ', $chooser_value ); |
| 1295 | + $chooser_text .= "<option value=\"$tabindex ,$chooser_value\">$chooser_caption</option>\n"; |
| 1296 | + } |
| 1297 | + $chooser_text .= "</select>\n"; |
| 1298 | + } |
| 1299 | + $chooser_text .= "<input type='button' onclick=\"addInstanceFromChooser('chooserselect$chooser_count');\" value='" . wfMsg( 'sf_formedit_addanother' ) . "' disabled='true' id='chooserbutton$chooser_count'></p>"; |
| 1300 | + } |
| 1301 | + |
| 1302 | + $form_text = str_replace( '{{{choosers}}}', $chooser_text, $form_text ); |
| 1303 | + |
| 1304 | + // add form bottom, if no custom "standard inputs" have been defined |
| 1305 | + if ( !$this->standardInputsIncluded ) { |
| 1306 | + if ( $is_query ) |
| 1307 | + $form_text .= SFFormUtils::queryFormBottom( $form_is_disabled ); |
| 1308 | + else |
| 1309 | + $form_text .= SFFormUtils::formBottom( $form_is_disabled ); |
| 1310 | + } |
| 1311 | + $starttime = wfTimestampNow(); |
| 1312 | + $page_article = new Article( $this->mPageTitle ); |
| 1313 | + $edittime = $page_article->getTimestamp(); |
| 1314 | + if ( !$is_query ) |
| 1315 | + $form_text .= <<<END |
| 1316 | + |
| 1317 | + <input type="hidden" value="$starttime" name="wpStarttime" /> |
| 1318 | + <input type="hidden" value="$edittime" name="wpEdittime" /> |
| 1319 | +END; |
| 1320 | + $form_text .= <<<END |
| 1321 | + </form> |
| 1322 | + |
| 1323 | +END; |
| 1324 | + |
| 1325 | + // add Javascript code for form-wide use |
| 1326 | + $javascript_text .= SFFormUtils::validationJavascript(); |
| 1327 | + $javascript_text .= SFFormUtils::instancesJavascript( $using_choosers ); |
| 1328 | + $javascript_text .= SFFormUtils::autocompletionJavascript(); |
| 1329 | + if ( $free_text_was_included && $showFCKEditor > 0 ) { |
| 1330 | + $javascript_text .= SFFormUtils::mainFCKJavascript( $showFCKEditor ); |
| 1331 | + if ( $showFCKEditor & ( RTE_TOGGLE_LINK | RTE_POPUP ) ) { |
| 1332 | + $javascript_text .= SFFormUTils::FCKToggleJavascript(); |
| 1333 | + } |
| 1334 | + if ( $showFCKEditor & RTE_POPUP ) { |
| 1335 | + $javascript_text .= SFFormUTils::FCKPopupJavascript(); |
| 1336 | + } |
| 1337 | + } |
| 1338 | + |
| 1339 | + // send the autocomplete values to the browser, along with the mappings |
| 1340 | + // of which values should apply to which fields |
| 1341 | + // if doing a replace, the data text is actually the modified original page |
| 1342 | + if ( $wgRequest->getCheck( 'partial' ) ) |
| 1343 | + $data_text = $existing_page_content; |
| 1344 | + $javascript_text .= $fields_javascript_text; |
| 1345 | + global $wgParser; |
| 1346 | + $new_text = ""; |
| 1347 | + if ( !$embedded ) |
| 1348 | + $new_text = $wgParser->preprocess( str_replace( "{{!}}", "|", $form_page_title ), $this->mPageTitle, new ParserOptions() ); |
| 1349 | + |
| 1350 | + return array( $form_text, "/*<![CDATA[*/ $javascript_text /*]]>*/", |
| 1351 | + $data_text, $new_text, $generated_page_name ); |
| 1352 | + } |
| 1353 | + |
| 1354 | + /** |
| 1355 | + * Create the HTML and Javascript to display this field within a form |
| 1356 | + */ |
| 1357 | + function formFieldHTML( $form_field, $cur_value ) { |
| 1358 | + global $smwgContLang; |
| 1359 | + |
| 1360 | + // also get the actual field, with all the semantic information (type is |
| 1361 | + // SFTemplateField, instead of SFFormField) |
| 1362 | + $template_field = $form_field->template_field; |
| 1363 | + |
| 1364 | + if ( $form_field->is_hidden ) { |
| 1365 | + $text = SFFormUtils::hiddenFieldHTML( $form_field->input_name, $cur_value ); |
| 1366 | + $javascript_text = ""; |
| 1367 | + } elseif ( $form_field->input_type != '' && |
| 1368 | + array_key_exists( $form_field->input_type, $this->mInputTypeHooks ) && |
| 1369 | + $this->mInputTypeHooks[$form_field->input_type] != null ) { |
| 1370 | + $funcArgs = array(); |
| 1371 | + $funcArgs[] = $cur_value; |
| 1372 | + $funcArgs[] = $form_field->input_name; |
| 1373 | + $funcArgs[] = $form_field->is_mandatory; |
| 1374 | + $funcArgs[] = $form_field->is_disabled; |
| 1375 | + // last argument to function should be a hash, merging the default |
| 1376 | + // values for this input type with all other properties set in |
| 1377 | + // the form definition, plus some semantic-related arguments |
| 1378 | + $hook_values = $this->mInputTypeHooks[$form_field->input_type]; |
| 1379 | + $other_args = $form_field->getArgumentsForInputCall( $hook_values[1] ); |
| 1380 | + $funcArgs[] = $other_args; |
| 1381 | + list( $text, $javascript_text ) = call_user_func_array( $hook_values[0], $funcArgs ); |
| 1382 | + } else { // input type not defined in form |
| 1383 | + $field_type = $template_field->field_type; |
| 1384 | + $is_list = ( $form_field->is_list || $template_field->is_list ); |
| 1385 | + if ( $field_type != '' && |
| 1386 | + array_key_exists( $field_type, $this->mSemanticTypeHooks ) && |
| 1387 | + isset( $this->mSemanticTypeHooks[$field_type][$is_list] ) ) { |
| 1388 | + $funcArgs = array(); |
| 1389 | + $funcArgs[] = $cur_value; |
| 1390 | + $funcArgs[] = $form_field->input_name; |
| 1391 | + $funcArgs[] = $form_field->is_mandatory; |
| 1392 | + $funcArgs[] = $form_field->is_disabled; |
| 1393 | + $hook_values = $this->mSemanticTypeHooks[$field_type][$is_list]; |
| 1394 | + $other_args = $form_field->getArgumentsForInputCall( $hook_values[1] ); |
| 1395 | + $funcArgs[] = $other_args; |
| 1396 | + list( $text, $javascript_text ) = call_user_func_array( $hook_values[0], $funcArgs ); |
| 1397 | + } else { // anything else |
| 1398 | + $other_args = $form_field->getArgumentsForInputCall(); |
| 1399 | + // special call to ensure that a list input is the right default size |
| 1400 | + if ( $form_field->is_list ) { |
| 1401 | + if ( ! array_key_exists( 'size', $other_args ) ) |
| 1402 | + $other_args['size'] = 100; |
| 1403 | + } |
| 1404 | + list( $text, $javascript_text ) = SFFormInputs::textEntryHTML( $cur_value, $form_field->input_name, $form_field->is_mandatory, $form_field->is_disabled, $other_args ); |
| 1405 | + } |
| 1406 | + } |
| 1407 | + return array( $text, $javascript_text ); |
| 1408 | + } |
| 1409 | + |
| 1410 | +} |
Property changes on: trunk/extensions/SemanticForms/includes/SF_FormPrinter.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 1411 | + native |
Index: trunk/extensions/SemanticForms/includes/SF_GlobalFunctions.php |
— | — | @@ -84,17 +84,17 @@ |
85 | 85 | $wgSpecialPages['UploadWindow'] = 'SFUploadWindow'; |
86 | 86 | $wgAutoloadClasses['SFUploadWindow'] = $sfgIP . '/specials/SF_UploadWindow.php'; |
87 | 87 | } |
88 | | -$wgAutoloadClasses['SFTemplateField'] = $sfgIP . '/includes/SF_TemplateField.inc'; |
89 | | -$wgAutoloadClasses['SFForm'] = $sfgIP . '/includes/SF_FormClasses.inc'; |
90 | | -$wgAutoloadClasses['SFTemplateInForm'] = $sfgIP . '/includes/SF_FormClasses.inc'; |
91 | | -$wgAutoloadClasses['SFFormField'] = $sfgIP . '/includes/SF_FormField.inc'; |
92 | | -$wgAutoloadClasses['SFFormPrinter'] = $sfgIP . '/includes/SF_FormPrinter.inc'; |
93 | | -$wgAutoloadClasses['SFFormInputs'] = $sfgIP . '/includes/SF_FormInputs.inc'; |
94 | | -$wgAutoloadClasses['SFFormUtils'] = $sfgIP . '/includes/SF_FormUtils.inc'; |
| 88 | +$wgAutoloadClasses['SFTemplateField'] = $sfgIP . '/includes/SF_TemplateField.php'; |
| 89 | +$wgAutoloadClasses['SFForm'] = $sfgIP . '/includes/SF_FormClasses.php'; |
| 90 | +$wgAutoloadClasses['SFTemplateInForm'] = $sfgIP . '/includes/SF_FormClasses.php'; |
| 91 | +$wgAutoloadClasses['SFFormField'] = $sfgIP . '/includes/SF_FormField.php'; |
| 92 | +$wgAutoloadClasses['SFFormPrinter'] = $sfgIP . '/includes/SF_FormPrinter.php'; |
| 93 | +$wgAutoloadClasses['SFFormInputs'] = $sfgIP . '/includes/SF_FormInputs.php'; |
| 94 | +$wgAutoloadClasses['SFFormUtils'] = $sfgIP . '/includes/SF_FormUtils.php'; |
95 | 95 | $wgAutoloadClasses['SFFormEditTab'] = $sfgIP . '/includes/SF_FormEditTab.php'; |
96 | 96 | $wgAutoloadClasses['SFFormEditPage'] = $sfgIP . '/includes/SF_FormEditPage.php'; |
97 | | -$wgAutoloadClasses['SFUtils'] = $sfgIP . '/includes/SF_Utils.inc'; |
98 | | -$wgAutoloadClasses['SFLinkUtils'] = $sfgIP . '/includes/SF_LinkUtils.inc'; |
| 97 | +$wgAutoloadClasses['SFUtils'] = $sfgIP . '/includes/SF_Utils.php'; |
| 98 | +$wgAutoloadClasses['SFLinkUtils'] = $sfgIP . '/includes/SF_LinkUtils.php'; |
99 | 99 | $wgAutoloadClasses['SFParserFunctions'] = $sfgIP . '/includes/SF_ParserFunctions.php'; |
100 | 100 | $wgAutoloadClasses['SFAutocompleteAPI'] = $sfgIP . '/includes/SF_AutocompleteAPI.php'; |
101 | 101 | $wgJobClasses['createPage'] = 'SFCreatePageJob'; |
Index: trunk/extensions/SemanticForms/includes/SF_LinkUtils.php |
— | — | @@ -0,0 +1,305 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Helper functions for linking to pages and forms |
| 5 | + * |
| 6 | + * @author Yaron Koren |
| 7 | + */ |
| 8 | + |
| 9 | +if ( !defined( 'MEDIAWIKI' ) ) die(); |
| 10 | + |
| 11 | +class SFLinkUtils { |
| 12 | + |
| 13 | + static function linkText( $namespace, $name, $text = NULL ) { |
| 14 | + global $wgContLang; |
| 15 | + |
| 16 | + $inText = $wgContLang->getNsText( $namespace ) . ':' . $name; |
| 17 | + $title = Title::newFromText( $inText ); |
| 18 | + if ( $title === NULL ) { |
| 19 | + return $inText; // TODO maybe report an error here? |
| 20 | + } |
| 21 | + if ( NULL === $text ) $text = $title->getText(); |
| 22 | + $l = new Linker(); |
| 23 | + return $l->makeLinkObj( $title, $text ); |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * Creates the name of the page that appears in the URL; |
| 28 | + * this method is necessary because Title::getPartialURL(), for |
| 29 | + * some reason, doesn't include the namespace |
| 30 | + */ |
| 31 | + static function titleURLString( $title ) { |
| 32 | + global $wgCapitalLinks; |
| 33 | + |
| 34 | + $namespace = wfUrlencode( $title->getNsText() ); |
| 35 | + if ( '' != $namespace ) { |
| 36 | + $namespace .= ':'; |
| 37 | + } |
| 38 | + if ( $wgCapitalLinks ) { |
| 39 | + global $wgContLang; |
| 40 | + return $namespace . $wgContLang->ucfirst( $title->getPartialURL() ); |
| 41 | + } else { |
| 42 | + return $namespace . $title->getPartialURL(); |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + /** |
| 47 | + * A very similar function to titleURLString(), to get the |
| 48 | + * non-URL-encoded title string |
| 49 | + */ |
| 50 | + static function titleString( $title ) { |
| 51 | + global $wgCapitalLinks; |
| 52 | + |
| 53 | + $namespace = $title->getNsText(); |
| 54 | + if ( '' != $namespace ) { |
| 55 | + $namespace .= ':'; |
| 56 | + } |
| 57 | + if ( $wgCapitalLinks ) { |
| 58 | + global $wgContLang; |
| 59 | + return $namespace . $wgContLang->ucfirst( $title->getText() ); |
| 60 | + } else { |
| 61 | + return $namespace . $title->getText(); |
| 62 | + } |
| 63 | + } |
| 64 | + |
| 65 | + /** |
| 66 | + * Gets the forms specified, if any, of either type "default form", |
| 67 | + * "alternate form", or "default form for page", for a specific page |
| 68 | + * (which should be a category, property, or namespace page) |
| 69 | + */ |
| 70 | + static function getFormsThatPagePointsTo( $page_name, $page_namespace, $prop_smw_id, $backup_prop_smw_id, $prop_id ) { |
| 71 | + if ( $page_name == NULL ) |
| 72 | + return array(); |
| 73 | + |
| 74 | + global $sfgContLang; |
| 75 | + // produce a useful error message if SMW isn't installed |
| 76 | + if ( ! function_exists( 'smwfGetStore' ) ) |
| 77 | + die( "ERROR: <a href=\"http://semantic-mediawiki.org\">Semantic MediaWiki</a> must be installed for Semantic Forms to run!" ); |
| 78 | + $store = smwfGetStore(); |
| 79 | + $title = Title::makeTitleSafe( $page_namespace, $page_name ); |
| 80 | + $property = SMWPropertyValue::makeProperty( $prop_smw_id ); |
| 81 | + $res = $store->getPropertyValues( $title, $property ); |
| 82 | + $form_names = array(); |
| 83 | + foreach ( $res as $wiki_page_value ) { |
| 84 | + $form_title = $wiki_page_value->getTitle(); |
| 85 | + if ( ! is_null( $form_title ) ) { |
| 86 | + $form_names[] = $form_title->getText(); |
| 87 | + } |
| 88 | + } |
| 89 | + // if we're using a non-English language, check for the English string as well |
| 90 | + if ( ! class_exists( 'SF_LanguageEn' ) || ! $sfgContLang instanceof SF_LanguageEn ) { |
| 91 | + $backup_property = SMWPropertyValue::makeProperty( $backup_prop_smw_id ); |
| 92 | + $res = $store->getPropertyValues( $title, $backup_property ); |
| 93 | + foreach ( $res as $wiki_page_value ) |
| 94 | + $form_names[] = $wiki_page_value->getTitle()->getText(); |
| 95 | + } |
| 96 | + return $form_names; |
| 97 | + } |
| 98 | + |
| 99 | + /** |
| 100 | + * Helper function for formEditLink() - gets the 'default form' and |
| 101 | + * 'alternate form' properties for a page, and creates the |
| 102 | + * corresponding Special:FormEdit link, if any such properties are |
| 103 | + * defined |
| 104 | + */ |
| 105 | + static function getFormEditLinkForPage( $target_page_title, $page_name, $page_namespace ) { |
| 106 | + $default_forms = self::getFormsThatPagePointsTo( $page_name, $page_namespace, '_SF_DF', '_SF_DF_BACKUP', SF_SP_HAS_DEFAULT_FORM ); |
| 107 | + $alt_forms = self::getFormsThatPagePointsTo( $page_name, $page_namespace, '_SF_AF', '_SF_AF_BACKUP', SF_SP_HAS_ALTERNATE_FORM ); |
| 108 | + if ( ( count( $default_forms ) == 0 ) && ( count( $alt_forms ) == 0 ) ) |
| 109 | + return null; |
| 110 | + $fe = SpecialPage::getPage( 'FormEdit' ); |
| 111 | + $fe_url = $fe->getTitle()->getLocalURL(); |
| 112 | + if ( count( $default_forms ) > 0 ) |
| 113 | + $form_edit_url = $fe_url . "/" . $default_forms[0] . "/" . self::titleURLString( $target_page_title ); |
| 114 | + else |
| 115 | + $form_edit_url = $fe_url . "/" . self::titleURLString( $target_page_title ); |
| 116 | + foreach ( $alt_forms as $i => $alt_form ) { |
| 117 | + $form_edit_url .= ( strpos( $form_edit_url, "?" ) ) ? "&" : "?"; |
| 118 | + $form_edit_url .= "alt_form[$i]=$alt_form"; |
| 119 | + } |
| 120 | + return $form_edit_url; |
| 121 | + } |
| 122 | + |
| 123 | + /** |
| 124 | + * Sets the URL for form-based creation of a nonexistent (broken-linked, |
| 125 | + * AKA red-linked) page, for MediaWiki 1.13 |
| 126 | + */ |
| 127 | + static function setBrokenLink_1_13( &$linker, $title, $query, &$u, &$style, &$prefix, &$text, &$inside, &$trail ) { |
| 128 | + if ( self::createLinkedPage( $title ) ) { |
| 129 | + return true; |
| 130 | + } |
| 131 | + $link = self::formEditLink( $title ); |
| 132 | + if ( $link != '' ) |
| 133 | + $u = $link; |
| 134 | + return true; |
| 135 | + } |
| 136 | + |
| 137 | + /** |
| 138 | + * Sets the URL for form-based creation of a nonexistent (broken-linked, |
| 139 | + * AKA red-linked) page |
| 140 | + */ |
| 141 | + static function setBrokenLink( $linker, $target, $options, $text, &$attribs, &$ret ) { |
| 142 | + if ( in_array( 'broken', $options ) ) { |
| 143 | + if ( self::createLinkedPage( $target ) ) { |
| 144 | + return true; |
| 145 | + } |
| 146 | + $link = self::formEditLink( $target ); |
| 147 | + if ( $link != '' ) { |
| 148 | + $attribs['href'] = $link; |
| 149 | + } |
| 150 | + } |
| 151 | + return true; |
| 152 | + } |
| 153 | + |
| 154 | + /** |
| 155 | + * Automatically creates a page that's red-linked from the page being |
| 156 | + * viewed, if there's a property pointing from anywhere to that page |
| 157 | + * that's defined with the 'Creates pages with form' special property |
| 158 | + */ |
| 159 | + static function createLinkedPage( $title ) { |
| 160 | + // if we're in a 'special' page, just exit - this is to prevent |
| 161 | + // constant additions being made from the 'Special:RecentChanges' |
| 162 | + // page, which shows pages that were previously deleted as red |
| 163 | + // links, even if they've since been recreated. The same might |
| 164 | + // hold true for other special pages. |
| 165 | + global $wgTitle; |
| 166 | + if ( $wgTitle->getNamespace() == NS_SPECIAL ) |
| 167 | + return false; |
| 168 | + |
| 169 | + $store = smwfGetStore(); |
| 170 | + $title_text = self::titleString( $title ); |
| 171 | + $value = SMWDataValueFactory::newTypeIDValue( '_wpg', $title_text ); |
| 172 | + $incoming_properties = $store->getInProperties( $value ); |
| 173 | + foreach ( $incoming_properties as $property ) { |
| 174 | + $property_name = $property->getWikiValue(); |
| 175 | + if ( empty( $property_name ) ) continue; |
| 176 | + $property_title = Title::makeTitleSafe( SMW_NS_PROPERTY, $property_name ); |
| 177 | + $auto_create_forms = self::getFormsThatPagePointsTo( $property_name, SMW_NS_PROPERTY, '_SF_CP', '_SF_CP_BACKUP', SF_SP_CREATES_PAGES_WITH_FORM ); |
| 178 | + if ( count( $auto_create_forms ) > 0 ) { |
| 179 | + global $sfgFormPrinter; |
| 180 | + $form_name = $auto_create_forms[0]; |
| 181 | + $form_title = Title::makeTitleSafe( SF_NS_FORM, $form_name ); |
| 182 | + $form_article = new Article( $form_title ); |
| 183 | + $form_definition = $form_article->getContent(); |
| 184 | + list ( $form_text, $javascript_text, $data_text, $form_page_title, $generated_page_name ) = |
| 185 | + $sfgFormPrinter->formHTML( $form_definition, false, false, null, null, 'Some very long page name that will hopefully never get created ABCDEF123', null ); |
| 186 | + $params = array(); |
| 187 | + global $wgUser; |
| 188 | + $params['user_id'] = $wgUser->getId(); |
| 189 | + $params['page_text'] = $data_text; |
| 190 | + $job = new SFCreatePageJob( $title, $params ); |
| 191 | + Job::batchInsert( array( $job ) ); |
| 192 | + |
| 193 | + return true; |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + return false; |
| 198 | + } |
| 199 | + |
| 200 | + /** |
| 201 | + * Returns the URL for the Special:FormEdit page for a specific page, |
| 202 | + * given its default and alternate form(s) - we can't just point to |
| 203 | + * '&action=formedit', because that one doesn't reflect alternate forms |
| 204 | + */ |
| 205 | + static function formEditLink( $title ) { |
| 206 | + // get all properties pointing to this page, and if |
| 207 | + // getFormEditLinkForPage() returns a value with any of |
| 208 | + // them, return that |
| 209 | + |
| 210 | + // produce a useful error message if SMW isn't installed |
| 211 | + if ( ! function_exists( 'smwfGetStore' ) ) |
| 212 | + die( "ERROR: <a href=\"http://semantic-mediawiki.org\">Semantic MediaWiki</a> must be installed for Semantic Forms to run!" ); |
| 213 | + $store = smwfGetStore(); |
| 214 | + $title_text = self::titleString( $title ); |
| 215 | + $value = SMWDataValueFactory::newTypeIDValue( '_wpg', $title_text ); |
| 216 | + $incoming_properties = $store->getInProperties( $value ); |
| 217 | + foreach ( $incoming_properties as $property ) { |
| 218 | + $property_title = $property->getWikiValue(); |
| 219 | + if ( $form_edit_link = self::getFormEditLinkForPage( $title, $property_title, SMW_NS_PROPERTY ) ) { |
| 220 | + return $form_edit_link; |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + // if that didn't work, check if this page's namespace |
| 225 | + // has a default form specified |
| 226 | + $namespace = $title->getNsText(); |
| 227 | + if ( '' === $namespace ) { |
| 228 | + // if it's in the main (blank) namespace, check for the |
| 229 | + // file named with the word for "Main" in this language |
| 230 | + wfLoadExtensionMessages( 'SemanticForms' ); |
| 231 | + $namespace = wfMsgForContent( 'sf_blank_namespace' ); |
| 232 | + } |
| 233 | + if ( $form_edit_link = self::getFormEditLinkForPage( $title, $namespace, NS_PROJECT ) ) { |
| 234 | + return $form_edit_link; |
| 235 | + } |
| 236 | + // if nothing found still, return null |
| 237 | + return null; |
| 238 | + } |
| 239 | + |
| 240 | + /** |
| 241 | + * Helper function - gets names of categories for a page; |
| 242 | + * based on Title::getParentCategories(), but simpler |
| 243 | + * - this function doubles as a function to get all categories on |
| 244 | + * the site, if no article is specified |
| 245 | + */ |
| 246 | + static function getCategoriesForArticle( $article = NULL ) { |
| 247 | + $categories = array(); |
| 248 | + $db = wfGetDB( DB_SLAVE ); |
| 249 | + $conditions = null; |
| 250 | + if ( $article != NULL ) { |
| 251 | + $titlekey = $article->mTitle->getArticleId(); |
| 252 | + $conditions = "cl_from='$titlekey'"; |
| 253 | + } |
| 254 | + $res = $db->select( $db->tableName( 'categorylinks' ), |
| 255 | + 'distinct cl_to', $conditions, __METHOD__ ); |
| 256 | + if ( $db->numRows( $res ) > 0 ) { |
| 257 | + while ( $row = $db->fetchRow( $res ) ) { |
| 258 | + $categories[] = $row[0]; |
| 259 | + } |
| 260 | + } |
| 261 | + $db->freeResult( $res ); |
| 262 | + return $categories; |
| 263 | + } |
| 264 | + |
| 265 | + /** |
| 266 | + * Get the form used to edit this article - either: |
| 267 | + * - the default form the page itself, if there is one; or |
| 268 | + * - the default form for a category that this article belongs to, |
| 269 | + * if there is one; or |
| 270 | + * - the default form for the article's namespace, if there is one |
| 271 | + */ |
| 272 | + static function getFormsForArticle( $obj ) { |
| 273 | + // see if the page itself has a default form (or forms), and |
| 274 | + // return it/them if so |
| 275 | + $default_forms = self::getFormsThatPagePointsTo( $obj->mTitle->getText(), $obj->mTitle->getNamespace(), '_SF_PDF', '_SF_PDF_BACKUP', SF_SP_PAGE_HAS_DEFAULT_FORM ); |
| 276 | + if ( count( $default_forms ) > 0 ) |
| 277 | + return $default_forms; |
| 278 | + // if this is not a category page, look for a default form |
| 279 | + // for its parent categories |
| 280 | + $namespace = $obj->mTitle->getNamespace(); |
| 281 | + if ( NS_CATEGORY !== $namespace ) { |
| 282 | + $default_forms = array(); |
| 283 | + $categories = self::getCategoriesForArticle( $obj ); |
| 284 | + foreach ( $categories as $category ) { |
| 285 | + $default_forms = array_merge( $default_forms, self::getFormsThatPagePointsTo( $category, NS_CATEGORY, '_SF_DF', '_SF_DF_BACKUP', SF_SP_HAS_DEFAULT_FORM ) ); |
| 286 | + } |
| 287 | + if ( count( $default_forms ) > 0 ) |
| 288 | + return $default_forms; |
| 289 | + } |
| 290 | + // if we're still here, just return the default form for the |
| 291 | + // namespace, which may well be null |
| 292 | + if ( NS_MAIN === $namespace ) { |
| 293 | + // if it's in the main (blank) namespace, check for the |
| 294 | + // file named with the word for "Main" in this language |
| 295 | + wfLoadExtensionMessages( 'SemanticForms' ); |
| 296 | + $namespace_label = wfMsgForContent( 'sf_blank_namespace' ); |
| 297 | + } else { |
| 298 | + global $wgContLang; |
| 299 | + $namespace_labels = $wgContLang->getNamespaces(); |
| 300 | + $namespace_label = $namespace_labels[$namespace]; |
| 301 | + } |
| 302 | + $default_forms = self::getFormsThatPagePointsTo( $namespace_label, NS_PROJECT, '_SF_DF', '_SF_DF_BACKUP', SF_SP_HAS_DEFAULT_FORM ); |
| 303 | + return $default_forms; |
| 304 | + } |
| 305 | + |
| 306 | +} |
Property changes on: trunk/extensions/SemanticForms/includes/SF_LinkUtils.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 307 | + native |
Index: trunk/extensions/SemanticForms/includes/SF_TemplateField.php |
— | — | @@ -0,0 +1,195 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Defines a class, SFTemplateField, that represents a field in a template, |
| 5 | + * including any possible semantic aspects it may have. Used in both creating |
| 6 | + * templates and displaying user-created forms |
| 7 | + * |
| 8 | + * @author Yaron Koren |
| 9 | + */ |
| 10 | + |
| 11 | +class SFTemplateField { |
| 12 | + var $field_name; |
| 13 | + var $value_labels; |
| 14 | + var $label; |
| 15 | + var $semantic_property; |
| 16 | + var $field_type; |
| 17 | + var $possible_values; |
| 18 | + var $is_list; |
| 19 | + var $input_type; |
| 20 | + |
| 21 | + static function create( $name, $label ) { |
| 22 | + $f = new SFTemplateField(); |
| 23 | + $f->field_name = trim( str_replace( '\\', '', $name ) ); |
| 24 | + $f->label = trim( str_replace( '\\', '', $label ) ); |
| 25 | + return $f; |
| 26 | + } |
| 27 | + |
| 28 | + /** |
| 29 | + * Create an SFTemplateField object based on the corresponding field |
| 30 | + * in the template definition (which we first have to find) |
| 31 | + */ |
| 32 | + static function createFromList( $field_name, $all_fields, $strict_parsing ) { |
| 33 | + // see if this field matches one of the fields defined for |
| 34 | + // the template it's part of - if it is, use all available |
| 35 | + // information about that field; if it's not, either create |
| 36 | + // an object for it or not, depending on whether the |
| 37 | + // template has a 'strict' setting in the form definition |
| 38 | + $the_field = null; |
| 39 | + foreach ( $all_fields as $cur_field ) { |
| 40 | + if ( $field_name == $cur_field->field_name ) { |
| 41 | + $the_field = $cur_field; |
| 42 | + break; |
| 43 | + } |
| 44 | + } |
| 45 | + if ( $the_field == null ) { |
| 46 | + if ( $strict_parsing ) { |
| 47 | + return null; |
| 48 | + } |
| 49 | + $the_field = new SFTemplateField(); |
| 50 | + } |
| 51 | + return $the_field; |
| 52 | + } |
| 53 | + |
| 54 | + function setTypeAndPossibleValues() { |
| 55 | + $proptitle = Title::makeTitleSafe( SMW_NS_PROPERTY, $this->semantic_property ); |
| 56 | + if ( $proptitle === NULL ) |
| 57 | + return; |
| 58 | + $store = smwfGetStore(); |
| 59 | + $types = $store->getPropertyValues( $proptitle, SMWPropertyValue::makeUserProperty( "Has type" ) ); |
| 60 | + // this returns an array of objects |
| 61 | + $allowed_values = $store->getPropertyValues( $proptitle, SMWPropertyValue::makeUserProperty( "Allows value" ) ); |
| 62 | + $label_formats = $store->getPropertyValues( $proptitle, SMWPropertyValue::makeUserProperty( "Has field label format" ) ); |
| 63 | + // TODO - need handling for the case of more than one type |
| 64 | + if ( count( $types ) > 0 ) |
| 65 | + $this->field_type = $types[0]->getWikiValue(); |
| 66 | + |
| 67 | + foreach ( $allowed_values as $value ) { |
| 68 | + // HTML-unencode each value |
| 69 | + $wiki_value = html_entity_decode( $value->getWikiValue() ); |
| 70 | + $this->possible_values[] = $wiki_value; |
| 71 | + if ( count( $label_formats ) > 0 ) { |
| 72 | + $label_format = $label_formats[0]->getWikiValue(); |
| 73 | + $prop_instance = SMWDataValueFactory::findTypeID( $this->field_type ); |
| 74 | + $label_value = SMWDataValueFactory::newTypeIDValue( $prop_instance, $wiki_value ); |
| 75 | + $label_value->setOutputFormat( $label_format ); |
| 76 | + $this->value_labels[$wiki_value] = html_entity_decode( $label_value->getWikiValue() ); |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + // HACK - if there were any possible values, set the field |
| 81 | + // type to be 'enumeration', regardless of what the actual type is |
| 82 | + if ( count( $this->possible_values ) > 0 ) { |
| 83 | + $this->field_type = 'enumeration'; |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + /** |
| 88 | + * Called when template is parsed during the creation of a form |
| 89 | + */ |
| 90 | + function setSemanticProperty( $semantic_property ) { |
| 91 | + $this->semantic_property = str_replace( '\\', '', $semantic_property ); |
| 92 | + $this->possible_values = array(); |
| 93 | + // set field type and possible values, if any |
| 94 | + $this->setTypeAndPossibleValues(); |
| 95 | + } |
| 96 | + |
| 97 | + /** |
| 98 | + * Returns whether the semantic property represented by this field |
| 99 | + * has the passed-in type constant (e.g., '_str', '_wpg') |
| 100 | + */ |
| 101 | + function propertyIsOfType( $type_constant ) { |
| 102 | + global $smwgContLang; |
| 103 | + $datatypeLabels = $smwgContLang->getDatatypeLabels(); |
| 104 | + $page_type = $datatypeLabels[$type_constant]; |
| 105 | + return ( $this->field_type == $page_type ); |
| 106 | + } |
| 107 | + |
| 108 | + function createTemplateText( $template_name, $template_fields, $category, $aggregating_property, $aggregating_label, $template_format ) { |
| 109 | + $template_header = wfMsgForContent( 'sf_template_docu', $template_name ); |
| 110 | + $text = <<<END |
| 111 | +<noinclude> |
| 112 | +$template_header |
| 113 | +<pre> |
| 114 | + |
| 115 | +END; |
| 116 | + $text .= '{{' . $template_name; |
| 117 | + if ( count( $template_fields ) > 0 ) { $text .= "\n"; } |
| 118 | + foreach ( $template_fields as $field ) { |
| 119 | + $text .= "|" . $field->field_name . "=\n"; |
| 120 | + } |
| 121 | + $template_footer = wfMsgForContent( 'sf_template_docufooter' ); |
| 122 | + $text .= <<<END |
| 123 | +}} |
| 124 | +</pre> |
| 125 | +$template_footer |
| 126 | +</noinclude><includeonly> |
| 127 | + |
| 128 | +END; |
| 129 | + // topmost part depends on format |
| 130 | + if ( $template_format == 'infobox' ) { |
| 131 | + // CSS style can't be used, unfortunately, since most MediaWiki |
| 132 | + // setups don't have an 'infobox' or comparable CSS class |
| 133 | + $text .= <<<END |
| 134 | +{| style="width: 30em; font-size: 90%; border: 1px solid #aaaaaa; background-color: #f9f9f9; color: black; margin-bottom: 0.5em; margin-left: 1em; padding: 0.2em; float: right; clear: right; text-align:left;" |
| 135 | +! style="text-align: center; background-color:#ccccff;" colspan="2" |<big>{{PAGENAME}}</big> |
| 136 | +|- |
| 137 | + |
| 138 | +END; |
| 139 | + } else { |
| 140 | + $text .= '{| class="wikitable"' . "\n"; |
| 141 | + } |
| 142 | + |
| 143 | + foreach ( $template_fields as $i => $field ) { |
| 144 | + if ( $i > 0 ) { |
| 145 | + $text .= "|-\n"; |
| 146 | + } |
| 147 | + $text .= "! " . $field->label . "\n"; |
| 148 | + if ( $field->semantic_property == null || $field->semantic_property == '' ) { |
| 149 | + $text .= "| {{{" . $field->field_name . "|}}}\n"; |
| 150 | + // if this field is meant to contain a list, |
| 151 | + // add on an 'arraymap' function, that will |
| 152 | + // call this semantic markup tag on every |
| 153 | + // element in the list |
| 154 | + } elseif ( $field->is_list ) { |
| 155 | + // find a string that's not in the semantic |
| 156 | + // field call, to be used as the variable |
| 157 | + $var = "x"; // default - use this if all the attempts fail |
| 158 | + if ( strstr( $field->semantic_property, $var ) ) { |
| 159 | + $var_options = array( 'y', 'z', 'xx', 'yy', 'zz', 'aa', 'bb', 'cc' ); |
| 160 | + foreach ( $var_options as $option ) { |
| 161 | + if ( ! strstr( $field->semantic_property, $option ) ) { |
| 162 | + $var = $option; |
| 163 | + break; |
| 164 | + } |
| 165 | + } |
| 166 | + } |
| 167 | + $text .= "| {{#arraymap:{{{" . $field->field_name . "|}}}|,|$var|[[" . $field->semantic_property . "::$var]]}}\n"; |
| 168 | + } else { |
| 169 | + $text .= "| [[" . $field->semantic_property . "::{{{" . $field->field_name . "|}}}]]\n"; |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + // add a row with an inline query to this table, for aggregation, if |
| 174 | + // a property was specified |
| 175 | + if ( $aggregating_property != '' ) { |
| 176 | + if ( count( $template_fields ) > 0 ) { |
| 177 | + $text .= "|-\n"; |
| 178 | + } |
| 179 | + $text .= <<<END |
| 180 | +! $aggregating_label |
| 181 | +| {{#ask:[[$aggregating_property::{{SUBJECTPAGENAME}}]]|format=list}} |
| 182 | + |
| 183 | +END; |
| 184 | + } |
| 185 | + $text .= "|}\n"; |
| 186 | + if ( $category != '' ) { |
| 187 | + global $wgContLang; |
| 188 | + $namespace_labels = $wgContLang->getNamespaces(); |
| 189 | + $category_namespace = $namespace_labels[NS_CATEGORY]; |
| 190 | + $text .= "\n[[$category_namespace:$category]]\n"; |
| 191 | + } |
| 192 | + $text .= "</includeonly>\n"; |
| 193 | + |
| 194 | + return $text; |
| 195 | + } |
| 196 | +} |
Property changes on: trunk/extensions/SemanticForms/includes/SF_TemplateField.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 197 | + native |
Index: trunk/extensions/SemanticForms/includes/SF_Utils.php |
— | — | @@ -0,0 +1,415 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Helper functions for the Semantic Forms extension. |
| 5 | + * |
| 6 | + * @author Yaron Koren |
| 7 | + */ |
| 8 | + |
| 9 | +if ( !defined( 'MEDIAWIKI' ) ) die(); |
| 10 | + |
| 11 | +class SFUtils { |
| 12 | + |
| 13 | + static function initProperties() { |
| 14 | + global $sfgContLang; |
| 15 | + $sf_props = $sfgContLang->getPropertyLabels(); |
| 16 | + if ( array_key_exists( SF_SP_HAS_DEFAULT_FORM, $sf_props ) ) |
| 17 | + SMWPropertyValue::registerProperty( '_SF_DF', '__spf', $sf_props[SF_SP_HAS_DEFAULT_FORM], true ); |
| 18 | + if ( array_key_exists( SF_SP_HAS_ALTERNATE_FORM, $sf_props ) ) |
| 19 | + SMWPropertyValue::registerProperty( '_SF_AF', '__spf', $sf_props[SF_SP_HAS_ALTERNATE_FORM], true ); |
| 20 | + if ( array_key_exists( SF_SP_CREATES_PAGES_WITH_FORM, $sf_props ) ) |
| 21 | + SMWPropertyValue::registerProperty( '_SF_CP', '__spf', $sf_props[SF_SP_CREATES_PAGES_WITH_FORM], true ); |
| 22 | + if ( array_key_exists( SF_SP_PAGE_HAS_DEFAULT_FORM, $sf_props ) ) |
| 23 | + SMWPropertyValue::registerProperty( '_SF_PDF', '__spf', $sf_props[SF_SP_PAGE_HAS_DEFAULT_FORM], true ); |
| 24 | + if ( array_key_exists( SF_SP_HAS_FIELD_LABEL_FORMAT, $sf_props ) ) |
| 25 | + SMWPropertyValue::registerProperty( '_SF_FLF', '_str', $sf_props[SF_SP_HAS_FIELD_LABEL_FORMAT], true ); |
| 26 | + // also initialize hardcoded English values, if it's a non-English-language wiki |
| 27 | + SMWPropertyValue::registerProperty( '_SF_DF_BACKUP', '__spf', 'Has default form', true ); |
| 28 | + SMWPropertyValue::registerProperty( '_SF_AF_BACKUP', '__spf', 'Has alternate form', true ); |
| 29 | + SMWPropertyValue::registerProperty( '_SF_CP_BACKUP', '__spf', 'Creates pages with form', true ); |
| 30 | + SMWPropertyValue::registerProperty( '_SF_PDF_BACKUP', '__spf', 'Page has default form', true ); |
| 31 | + SMWPropertyValue::registerProperty( '_SF_FLF_BACKUP', '_str', 'Has field label format', true ); |
| 32 | + |
| 33 | + return true; |
| 34 | + } |
| 35 | + |
| 36 | + /** |
| 37 | + * Creates HTML linking to a wiki page |
| 38 | + */ |
| 39 | + static function linkText( $namespace, $name, $text = NULL ) { |
| 40 | + global $wgContLang; |
| 41 | + |
| 42 | + $title = Title::makeTitleSafe( $namespace, $name ); |
| 43 | + if ( $title === NULL ) { |
| 44 | + return $name; // TODO maybe report an error here? |
| 45 | + } |
| 46 | + if ( NULL === $text ) $text = $title->getText(); |
| 47 | + $l = new Linker(); |
| 48 | + return $l->makeLinkObj( $title, $text ); |
| 49 | + } |
| 50 | + |
| 51 | + /** |
| 52 | + * Prints the mini-form contained at the bottom of various pages, that |
| 53 | + * allows pages to spoof a normal edit page, that can preview, save, |
| 54 | + * etc. |
| 55 | + */ |
| 56 | + static function printRedirectForm( $title, $page_contents, $edit_summary, $is_save, $is_preview, $is_diff, $is_minor_edit, $watch_this, $start_time, $edit_time ) { |
| 57 | + if ( $title instanceof Title ) |
| 58 | + $new_url = $title->getLocalURL( 'action=submit' ); |
| 59 | + else |
| 60 | + $new_url = $title; |
| 61 | + global $wgUser; |
| 62 | + if ( $wgUser->isLoggedIn() ) |
| 63 | + $token = htmlspecialchars( $wgUser->editToken() ); |
| 64 | + else |
| 65 | + $token = EDIT_TOKEN_SUFFIX; |
| 66 | + |
| 67 | + $edit_summary = htmlspecialchars( $edit_summary ); |
| 68 | + if ( $is_save ) |
| 69 | + $action = "wpSave"; |
| 70 | + elseif ( $is_preview ) |
| 71 | + $action = "wpPreview"; |
| 72 | + else // $is_diff |
| 73 | + $action = "wpDiff"; |
| 74 | + |
| 75 | + global $sfgScriptPath; |
| 76 | + $text = <<<END |
| 77 | + <p style="position: absolute; left: 45%; top: 45%;"><img src="$sfgScriptPath/skins/loading.gif" /></p> |
| 78 | + |
| 79 | +END; |
| 80 | + $form_body = ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpTextbox1', 'id' => 'wpTextbox1', 'value' => $page_contents ), null ) . "\n"; |
| 81 | + $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpSummary', 'value' => $edit_summary ), null ) . "\n"; |
| 82 | + $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpStarttime', 'value' => $start_time ), null ) . "\n"; |
| 83 | + $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpEdittime', 'value' => $edit_time ), null ) . "\n"; |
| 84 | + $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpEditToken', 'value' => $token ), null ) . "\n"; |
| 85 | + $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => $action ), null ) . "\n"; |
| 86 | + |
| 87 | + if ( $is_minor_edit ) |
| 88 | + $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpMinorEdit' ), null ) . "\n"; |
| 89 | + if ( $watch_this ) |
| 90 | + $form_body .= ' ' . Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpWatchthis' ), null ) . "\n"; |
| 91 | + $text .= Xml::tags( 'form', array( 'id' => 'editform', 'name' => 'editform', 'method' => 'post', 'action' => $new_url ), $form_body ); |
| 92 | + |
| 93 | + $text .= <<<END |
| 94 | + <script type="text/javascript"> |
| 95 | + window.onload = function() { |
| 96 | + document.editform.submit(); |
| 97 | + } |
| 98 | + </script> |
| 99 | + |
| 100 | +END; |
| 101 | + wfRunHooks( 'sfPrintRedirectForm', array( $is_save, $is_preview, $is_diff, &$text ) ); |
| 102 | + return $text; |
| 103 | + } |
| 104 | + |
| 105 | + /** |
| 106 | + * Includes the necessary Javascript and CSS files for the form |
| 107 | + * to display and work correctly |
| 108 | + * |
| 109 | + * Accepts an optional Parser instance, or uses $wgOut if omitted. |
| 110 | + */ |
| 111 | + static function addJavascriptAndCSS( $parser = NULL ) { |
| 112 | + global $wgOut, $sfgScriptPath, $sfgYUIBase, $smwgScriptPath, $wgScriptPath, $wgFCKEditorDir, $wgJsMimeType, $sfgUseFormEditPage; |
| 113 | + |
| 114 | + $links = array( |
| 115 | + array( |
| 116 | + 'rel' => 'stylesheet', |
| 117 | + 'type' => 'text/css', |
| 118 | + 'media' => "screen", |
| 119 | + 'href' => $sfgScriptPath . '/skins/SF_main.css' |
| 120 | + ), |
| 121 | + array( |
| 122 | + 'rel' => 'stylesheet', |
| 123 | + 'type' => 'text/css', |
| 124 | + 'media' => "screen", |
| 125 | + 'href' => $sfgYUIBase . "autocomplete/assets/skins/sam/autocomplete.css" |
| 126 | + ), |
| 127 | + array( |
| 128 | + 'rel' => 'stylesheet', |
| 129 | + 'type' => 'text/css', |
| 130 | + 'media' => "screen", |
| 131 | + 'href' => $sfgScriptPath . '/skins/SF_yui_autocompletion.css' |
| 132 | + ), |
| 133 | + array( |
| 134 | + 'rel' => 'stylesheet', |
| 135 | + 'type' => 'text/css', |
| 136 | + 'media' => "screen", |
| 137 | + 'href' => $sfgScriptPath . '/skins/floatbox.css' |
| 138 | + ), |
| 139 | + array( |
| 140 | + 'rel' => 'stylesheet', |
| 141 | + 'type' => 'text/css', |
| 142 | + 'media' => "screen", |
| 143 | + 'href' => $smwgScriptPath . '/skins/SMW_custom.css' |
| 144 | + ), |
| 145 | + ); |
| 146 | + foreach ( $links as $link ) { |
| 147 | + if ( $parser ) |
| 148 | + $parser->getOutput()->addHeadItem( Xml::element( 'link', $link ) ); |
| 149 | + else |
| 150 | + $wgOut->addLink( $link ); |
| 151 | + } |
| 152 | + |
| 153 | + |
| 154 | + $scripts = array(); |
| 155 | + $scripts[] = "{$sfgYUIBase}yahoo/yahoo-min.js"; |
| 156 | + $scripts[] = "{$sfgYUIBase}dom/dom-min.js"; |
| 157 | + $scripts[] = "{$sfgYUIBase}event/event-min.js"; |
| 158 | + $scripts[] = "{$sfgYUIBase}get/get-min.js"; |
| 159 | + $scripts[] = "{$sfgYUIBase}connection/connection-min.js"; |
| 160 | + $scripts[] = "{$sfgYUIBase}json/json-min.js"; |
| 161 | + $scripts[] = "{$sfgYUIBase}datasource/datasource-min.js"; |
| 162 | + $scripts[] = "{$sfgYUIBase}autocomplete/autocomplete-min.js"; |
| 163 | + $scripts[] = "$sfgScriptPath/libs/SF_yui_autocompletion.js"; |
| 164 | + if ( !$sfgUseFormEditPage ) |
| 165 | + $scripts[] = "$sfgScriptPath/libs/SF_ajax_form_preview.js"; |
| 166 | + $scripts[] = "$sfgScriptPath/libs/floatbox.js"; |
| 167 | + $scripts[] = "$smwgScriptPath/skins/SMW_tooltip.js"; |
| 168 | + $scripts[] = "$smwgScriptPath/skins/SMW_sorttable.js"; |
| 169 | + if ( $wgFCKEditorDir ) |
| 170 | + $scripts[] = "$wgScriptPath/$wgFCKEditorDir/fckeditor.js"; |
| 171 | + foreach ( $scripts as $js ) { |
| 172 | + $script = "<script type=\"$wgJsMimeType\" src=\"$js\"></script>\n"; |
| 173 | + if ( $parser ) |
| 174 | + $parser->getOutput()->addHeadItem( $script ); |
| 175 | + else |
| 176 | + $wgOut->addScript( $script ); |
| 177 | + } |
| 178 | + if ( !$parser ) |
| 179 | + $wgOut->addMeta( 'robots', 'noindex,nofollow' ); |
| 180 | + } |
| 181 | + |
| 182 | + /** |
| 183 | + * Return an array of all form names on this wiki |
| 184 | + */ |
| 185 | + static function getAllForms() { |
| 186 | + $dbr = wfGetDB( DB_SLAVE ); |
| 187 | + $query = "SELECT page_title FROM " . $dbr->tableName( 'page' ) . |
| 188 | + " WHERE page_namespace = " . SF_NS_FORM . |
| 189 | + " AND page_is_redirect = 0" . |
| 190 | + " ORDER BY page_title"; |
| 191 | + $res = $dbr->query( $query ); |
| 192 | + $form_names = array(); |
| 193 | + while ( $row = $dbr->fetchRow( $res ) ) { |
| 194 | + $form_names[] = str_replace( '_', ' ', $row[0] ); |
| 195 | + } |
| 196 | + $dbr->freeResult( $res ); |
| 197 | + return $form_names; |
| 198 | + } |
| 199 | + |
| 200 | + static function formDropdownHTML() { |
| 201 | + // create a dropdown of possible form names |
| 202 | + global $sfgContLang; |
| 203 | + $namespace_labels = $sfgContLang->getNamespaces(); |
| 204 | + $form_label = $namespace_labels[SF_NS_FORM]; |
| 205 | + $form_names = SFUtils::getAllForms(); |
| 206 | + $select_body = ""; |
| 207 | + foreach ( $form_names as $form_name ) { |
| 208 | + $select_body .= ' ' . Xml::element( 'option', null, $form_name ) . "\n"; |
| 209 | + } |
| 210 | + $str = " $form_label:" . Xml::tags( 'select', array( 'name' => 'form' ), $select_body ) . "\n"; |
| 211 | + return $str; |
| 212 | + } |
| 213 | + |
| 214 | + /* |
| 215 | + * This function, unlike the others, doesn't take in a substring |
| 216 | + * because it uses the SMW data store, which can't perform |
| 217 | + * case-insensitive queries; for queries with a substring, the |
| 218 | + * function SFAutocompletAPI::getAllValuesForProperty() exists. |
| 219 | + */ |
| 220 | + static function getAllValuesForProperty( $property_name ) { |
| 221 | + global $sfgMaxAutocompleteValues; |
| 222 | + |
| 223 | + $store = smwfGetStore(); |
| 224 | + $requestoptions = new SMWRequestOptions(); |
| 225 | + $requestoptions->limit = $sfgMaxAutocompleteValues; |
| 226 | + $property = SMWPropertyValue::makeProperty( $property_name ); |
| 227 | + $data_values = $store->getPropertyValues( null, $property, $requestoptions ); |
| 228 | + $values = array(); |
| 229 | + foreach ( $data_values as $dv ) { |
| 230 | + // getPropertyValues() gets many repeat values - we want |
| 231 | + // only one of each value |
| 232 | + $string_value = str_replace( '_', ' ', $dv->getWikiValue() ); |
| 233 | + if ( array_search( $string_value, $values ) === false ) |
| 234 | + $values[] = $string_value; |
| 235 | + } |
| 236 | + return $values; |
| 237 | + } |
| 238 | + |
| 239 | + /* |
| 240 | + * Get all the pages that belong to a category and all its |
| 241 | + * subcategories, down a certain number of levels - heavily based on |
| 242 | + * SMW's SMWInlineQuery::includeSubcategories() |
| 243 | + */ |
| 244 | + static function getAllPagesForCategory( $top_category, $num_levels, $substring = null ) { |
| 245 | + if ( 0 == $num_levels ) return $top_category; |
| 246 | + global $sfgMaxAutocompleteValues; |
| 247 | + |
| 248 | + $db = wfGetDB( DB_SLAVE ); |
| 249 | + $top_category = str_replace( ' ', '_', $top_category ); |
| 250 | + $categories = array( $top_category ); |
| 251 | + $checkcategories = array( $top_category ); |
| 252 | + $pages = array(); |
| 253 | + for ( $level = $num_levels; $level > 0; $level-- ) { |
| 254 | + $newcategories = array(); |
| 255 | + foreach ( $checkcategories as $category ) { |
| 256 | + if ( $substring != null ) { |
| 257 | + $substring = str_replace( ' ', '_', strtolower( $substring ) ); |
| 258 | + $substring = str_replace( '_', '\_', $substring ); |
| 259 | + $substring = str_replace( "'", "\'", $substring ); |
| 260 | + $conditions = 'cl_to = ' . $db->addQuotes( $category ) . " AND (LOWER(CONVERT(`page_title` USING utf8)) LIKE '" . $substring . "%' OR LOWER(CONVERT(`page_title` USING utf8)) LIKE '%\_" . $substring . "%' OR page_namespace = " . NS_CATEGORY . ")"; |
| 261 | + } else { |
| 262 | + $conditions = 'cl_to = ' . $db->addQuotes( $category ); |
| 263 | + } |
| 264 | + $res = $db->select( // make the query |
| 265 | + array( 'categorylinks', 'page' ), |
| 266 | + array( 'page_title', 'page_namespace' ), |
| 267 | + array( 'cl_from = page_id', $conditions ), |
| 268 | + __METHOD__, |
| 269 | + 'SORT BY cl_sortkey' ); |
| 270 | + if ( $res ) { |
| 271 | + while ( $res && $row = $db->fetchRow( $res ) ) { |
| 272 | + if ( array_key_exists( 'page_title', $row ) ) { |
| 273 | + $page_namespace = $row['page_namespace']; |
| 274 | + if ( $page_namespace == NS_CATEGORY ) { |
| 275 | + $new_category = $row[ 'page_title' ]; |
| 276 | + if ( !in_array( $new_category, $categories ) ) { |
| 277 | + $newcategories[] = $new_category; |
| 278 | + } |
| 279 | + } else { |
| 280 | + $cur_value = str_replace( "_", " ", $row['page_title'] ); |
| 281 | + if ( ! in_array( $cur_value, $pages ) ) { |
| 282 | + if ( $substring == null ) |
| 283 | + $pages[] = $cur_value; |
| 284 | + else |
| 285 | + $pages[] = array( 'title' => $cur_value ); |
| 286 | + } |
| 287 | + // return if we've reached the maximum number of allowed values |
| 288 | + if ( count( $pages ) > $sfgMaxAutocompleteValues ) |
| 289 | + return $pages; |
| 290 | + } |
| 291 | + } |
| 292 | + } |
| 293 | + $db->freeResult( $res ); |
| 294 | + } |
| 295 | + } |
| 296 | + if ( count( $newcategories ) == 0 ) { |
| 297 | + return $pages; |
| 298 | + } else { |
| 299 | + $categories = array_merge( $categories, $newcategories ); |
| 300 | + } |
| 301 | + $checkcategories = array_diff( $newcategories, array() ); |
| 302 | + } |
| 303 | + return $pages; |
| 304 | + } |
| 305 | + |
| 306 | + static function getAllPagesForConcept( $concept_name, $substring = null ) { |
| 307 | + global $sfgMaxAutocompleteValues; |
| 308 | + |
| 309 | + // TODO - substring isn't being handled. Is there a way to |
| 310 | + // include it through the API? |
| 311 | + $store = smwfGetStore(); |
| 312 | +/* |
| 313 | + $requestoptions = new SMWRequestOptions(); |
| 314 | + if ($substring != null) { |
| 315 | + $requestoptions->addStringCondition($substring, SMWStringCondition::STRCOND_PRE); |
| 316 | + } |
| 317 | +*/ |
| 318 | + $concept = Title::makeTitleSafe( SMW_NS_CONCEPT, $concept_name ); |
| 319 | + // escape if there's a problem |
| 320 | + if ( $concept == null ) |
| 321 | + return array(); |
| 322 | + $desc = new SMWConceptDescription( $concept ); |
| 323 | + $printout = new SMWPrintRequest( SMWPrintRequest::PRINT_THIS, "" ); |
| 324 | + $desc->addPrintRequest( $printout ); |
| 325 | + $query = new SMWQuery( $desc ); |
| 326 | + $query->setLimit( $sfgMaxAutocompleteValues ); |
| 327 | + $query_result = $store->getQueryResult( $query ); |
| 328 | + $pages = array(); |
| 329 | + while ( $res = $query_result->getNext() ) { |
| 330 | + $pages[] = $res[0]->getNextText( SMW_OUTPUT_WIKI ); |
| 331 | + } |
| 332 | + sort( $pages ); |
| 333 | + return $pages; |
| 334 | + } |
| 335 | + |
| 336 | + static function getAllPagesForNamespace( $namespace_name, $substring = null ) { |
| 337 | + // cycle through all the namespace names for this language, and |
| 338 | + // if one matches the namespace specified in the form, add the |
| 339 | + // names of all the pages in that namespace to $names_array |
| 340 | + global $wgContLang; |
| 341 | + $namespaces = $wgContLang->getNamespaces(); |
| 342 | + $db = wfGetDB( DB_SLAVE ); |
| 343 | + $pages = array(); |
| 344 | + foreach ( $namespaces as $ns_code => $ns_name ) { |
| 345 | + if ( $ns_name == $namespace_name ) { |
| 346 | + $conditions = "page_namespace = $ns_code"; |
| 347 | + if ( $substring != null ) { |
| 348 | + $substring = str_replace( ' ', '_', strtolower( $substring ) ); |
| 349 | + $substring = str_replace( '_', '\_', $substring ); |
| 350 | + $substring = str_replace( "'", "\'", $substring ); |
| 351 | + $conditions .= " AND (LOWER(CONVERT(`page_title` USING utf8)) LIKE '$substring%' OR LOWER(CONVERT(`page_title` USING utf8)) LIKE '%\_$substring%')"; |
| 352 | + } |
| 353 | + $sql_options['ORDER BY'] = 'page_title'; |
| 354 | + $res = $db->select( $db->tableNames( 'page' ), |
| 355 | + 'page_title', |
| 356 | + $conditions, __METHOD__, $sql_options ); |
| 357 | + while ( $row = $db->fetchRow( $res ) ) { |
| 358 | + $cur_value = str_replace( '_', ' ', $row[0] ); |
| 359 | + if ( $substring == null ) { |
| 360 | + $pages[] = $cur_value; |
| 361 | + } else { |
| 362 | + $pages[] = array( 'title' => $cur_value ); |
| 363 | + } |
| 364 | + } |
| 365 | + $db->freeResult( $res ); |
| 366 | + } |
| 367 | + } |
| 368 | + return $pages; |
| 369 | + } |
| 370 | + |
| 371 | + static function getValuesFromExternalURL( $external_url_alias, $substring ) { |
| 372 | + global $sfgAutocompletionURLs; |
| 373 | + if ( empty( $sfgAutocompletionURLs ) ) return array(); |
| 374 | + $url = $sfgAutocompletionURLs[$external_url_alias]; |
| 375 | + if ( empty( $url ) ) return array(); |
| 376 | + $url = str_replace( '<substr>', $substring, $url ); |
| 377 | + $page_contents = Http::get( $url ); |
| 378 | + if ( empty( $page_contents ) ) return array(); |
| 379 | + $data = json_decode( $page_contents ); |
| 380 | + if ( empty( $data ) ) return array(); |
| 381 | + $return_values = array(); |
| 382 | + foreach ( $data->sfautocomplete as $val ) { |
| 383 | + $return_values[] = (array)$val; |
| 384 | + } |
| 385 | + return $return_values; |
| 386 | + } |
| 387 | + |
| 388 | + /** |
| 389 | + * Parse the form definition and store the resulting HTML in the |
| 390 | + * page_props table, if caching has been specified in LocalSettings.php |
| 391 | + */ |
| 392 | + function cacheFormDefinition( $parser, $text ) { |
| 393 | + global $sfgCacheFormDefinitions; |
| 394 | + if ( ! $sfgCacheFormDefinitions ) |
| 395 | + return true; |
| 396 | + |
| 397 | + $title = $parser->getTitle(); |
| 398 | + if ( empty( $title ) ) return true; |
| 399 | + if ( $title->getNamespace() != SF_NS_FORM ) return true; |
| 400 | + // Remove <noinclude> sections and <includeonly> tags from form definition |
| 401 | + $form_def = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $text ); |
| 402 | + $form_def = strtr( $form_def, array( '<includeonly>' => '', '</includeonly>' => '' ) ); |
| 403 | + |
| 404 | + // parse wiki-text |
| 405 | + // add '<nowiki>' tags around every triple-bracketed form |
| 406 | + // definition element, so that the wiki parser won't touch |
| 407 | + // it - the parser will remove the '<nowiki>' tags, leaving |
| 408 | + // us with what we need |
| 409 | + $form_def = "__NOEDITSECTION__" . strtr( $form_def, array( '{{{' => '<nowiki>{{{', '}}}' => '}}}</nowiki>' ) ); |
| 410 | + $dummy_title = Title::newFromText( 'Form definition title for caching purposes' ); |
| 411 | + $form_def = $parser->parse( $form_def, $dummy_title, $parser->mOptions )->getText(); |
| 412 | + |
| 413 | + $parser->mOutput->setProperty( 'formdefinition', $form_def ); |
| 414 | + return true; |
| 415 | + } |
| 416 | +} |
Property changes on: trunk/extensions/SemanticForms/includes/SF_Utils.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 417 | + native |