r65400 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r65399‎ | r65400 | r65401 >
Date:15:31, 21 April 2010
Author:yaron
Status:deferred
Tags:
Comment:
Renamed all Semantic Forms ".inc" files to ".php"
Modified paths:
  • /trunk/extensions/SemanticForms/includes/SF_FormClasses.inc (deleted) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormClasses.php (added) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormField.inc (deleted) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormField.php (added) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormInputs.inc (deleted) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormInputs.php (added) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormPrinter.inc (deleted) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormPrinter.php (added) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormUtils.inc (deleted) (history)
  • /trunk/extensions/SemanticForms/includes/SF_FormUtils.php (added) (history)
  • /trunk/extensions/SemanticForms/includes/SF_GlobalFunctions.php (modified) (history)
  • /trunk/extensions/SemanticForms/includes/SF_LinkUtils.inc (deleted) (history)
  • /trunk/extensions/SemanticForms/includes/SF_LinkUtils.php (added) (history)
  • /trunk/extensions/SemanticForms/includes/SF_TemplateField.inc (deleted) (history)
  • /trunk/extensions/SemanticForms/includes/SF_TemplateField.php (added) (history)
  • /trunk/extensions/SemanticForms/includes/SF_Utils.inc (deleted) (history)
  • /trunk/extensions/SemanticForms/includes/SF_Utils.php (added) (history)

Diff [purge]

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 .= ' &nbsp;<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 - &nbsp; $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( '&#123;', '&#124;', '&#125;' ), 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 '&gt;' 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( '&lt;page name&gt;', $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
1214 + 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
11110 + 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 .= ' &nbsp;<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
1897 + 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+ &nbsp; $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
1282 + 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( '&#123;', '&#124;', '&#125;' ), 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 '&gt;' 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( '&lt;page name&gt;', $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
11411 + native
Index: trunk/extensions/SemanticForms/includes/SF_GlobalFunctions.php
@@ -84,17 +84,17 @@
8585 $wgSpecialPages['UploadWindow'] = 'SFUploadWindow';
8686 $wgAutoloadClasses['SFUploadWindow'] = $sfgIP . '/specials/SF_UploadWindow.php';
8787 }
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';
9595 $wgAutoloadClasses['SFFormEditTab'] = $sfgIP . '/includes/SF_FormEditTab.php';
9696 $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';
9999 $wgAutoloadClasses['SFParserFunctions'] = $sfgIP . '/includes/SF_ParserFunctions.php';
100100 $wgAutoloadClasses['SFAutocompleteAPI'] = $sfgIP . '/includes/SF_AutocompleteAPI.php';
101101 $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
1307 + 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
1197 + 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
1417 + native

Status & tagging log