summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/SemanticMediaWiki/includes/SMW_Outputs.php
blob: 2d2c1e4fa28035692f43f931a662d62f0ee5d764 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
<?php

/**
 * This class attempts to provide safe yet simple means for managing data that is relevant
 * for the final HTML output of MediaWiki. In particular, this concerns additions to the HTML
 * header in the form of scripts of stylesheets.
 *
 * The problem is that many components in SMW create hypertext that should eventually be displayed.
 * The normal way of accessing such text are functions of the form getText() which return a
 * (hypertext) string. Such a string, however, might refer to styles or scripts that are also
 * needed. It is not possible to directly add those scripts to the MediaWiki output, since the form
 * of this output depends on the context in which the function is called. Many functions might be
 * called both during parsing and directly in special pages that do not use the usual parsing and
 * caching mechanisms.
 *
 * Ideally, all functions that generate hypertext with dependencies would also include parameters to
 * record required scripts. Since this would require major API changes, the current solution is to have
 * a "temporal" global storage for the required items, managed in this class. It is not safe to use
 * such a global store across hooks -- you never know what happens in between! Hence, every function
 * that creates SMW outputs that may require head items must afterwards clear the temporal store by
 * writing its contents to the according output.
 *
 * @ingroup SMW
 *
 * @author Markus Krötzsch
 */
class SMWOutputs {

	/**
	 * Protected member for temporarily storing header items.
	 * Format $id => $headItem where $id is used only to avoid duplicate
	 * items in the time before they are forwarded to the output.
	 */
	protected static $headItems = [];

	/**
	 * Protected member for temporarily storing additional Javascript
	 * snippets. Format $id => $scriptText where $id is used only to
	 * avoid duplicate scripts in the time before they are forwarded
	 * to the output.
	 */
	protected static $scripts = [];

	/**
	 * Protected member for temporarily storing resource modules.
	 *
	 * @var array
	 */
	protected static $resourceModules = [];

	/**
	 * Protected member for temporarily storing resource modules.
	 *
	 * @var array
	 */
	protected static $resourceStyles = [];

	/**
	 * Adds a resource module to the parser output.
	 *
	 * @since 1.5.3
	 *
	 * @param string $moduleName
	 */
	public static function requireResource( $moduleName ) {
		self::$resourceModules[$moduleName] = $moduleName;
	}

	/**
	 * @since 3.0
	 *
	 * @param string $stylesName
	 */
	public static function requireStyle( $stylesName ) {
		self::$resourceStyles[$stylesName] = $stylesName;
	}

	/**
	 * Require the presence of header scripts, provided as strings with
	 * enclosing script tags. Note that the same could be achieved with
	 * requireHeadItems, but scripts use a special method "addScript" in
	 * MediaWiki OutputPage, hence we distinguish them.
	 *
	 * The id is used to avoid that the requirement for one script is
	 * recorded multiple times in SMWOutputs.
	 *
	 * @param string $id
	 * @param string $item
	 */
	public static function requireScript( $id, $script ) {
		self::$scripts[$id] = $script;
	}

	/**
	 * Adds head items that are not Resource Loader modules. Should only
	 * be used for custom head items such as RSS fedd links.
	 *
	 * The id is used to avoid that the requirement for one script is
	 * recorded multiple times in SMWOutputs.
	 *
	 * Support for calling this with the old constants SMW_HEADER_STYLE
	 * and SMW_HEADER_TOOLTIP will vanish in SMW 1.7 at the latest.
	 *
	 * @param mixed $id
	 * @param string $item
	 */
	public static function requireHeadItem( $id, $item = '' ) {
		if ( is_numeric( $id ) ) {
			switch ( $id ) {
				case SMW_HEADER_TOOLTIP:
					self::requireResource( 'ext.smw.tooltips' );
				break;
				case SMW_HEADER_STYLE:
					self::requireStyle( 'ext.smw.style' );
				break;
			}
		} else {
			self::$headItems[$id] = $item;
		}
	}

	/**
	 * This function takes output requirements as can be found in a given ParserOutput
	 * object and puts them back in to the internal temporal requirement list from
	 * which they can be committed to some other output. It is needed when code that
	 * would normally call SMWOutputs::requireHeadItem() has need to use a full
	 * independent parser call (Parser::parse()) that produces its own parseroutput.
	 * If omitted, all output items potentially committed to this parseroutput during
	 * parsing will not be passed on to higher levels.
	 *
	 * Note that this is not required if the $parseroutput is further processed by
	 * MediaWiki, but there are cases where the output is discarded and only its text
	 * is used.
	 *
	 * @param ParserOutput $parserOutput
	 */
	static public function requireFromParserOutput( ParserOutput $parserOutput ) {
		// Note: we do not attempt to recover which head items where scripts here.

		$parserOutputHeadItems = $parserOutput->getHeadItems();

		self::$headItems = array_merge( (array)self::$headItems, $parserOutputHeadItems );

		/// TODO Is the following needed?
		if ( isset( $parserOutput->mModules ) ) {
			foreach ( $parserOutput->mModules as $module ) {
				self::$resourceModules[$module] = $module;
			}
		}
	}

	/**
	 * Actually commit the collected requirements to a given parser that is about to parse
	 * what will later be the HTML output. This makes sure that HTML output based on the
	 * parser results contains all required output items.
	 *
	 * If the parser creates output for a normal wiki page, then the committed items will
	 * also become part of the page cache so that they will correctly be added to all page
	 * outputs built from this cache later on.
	 *
	 * @param Parser $parser
	 */
	static public function commitToParser( Parser $parser ) {
		/// TODO find out and document when this b/c code can go away
		if ( method_exists( $parser, 'getOutput' ) ) {
			$po = $parser->getOutput();
		} else {
			$po = $parser->mOutput;
		}

		if ( isset( $po ) ) {
			self::commitToParserOutput( $po );
		}
	}

	/**
	 * Similar to SMWOutputs::commitToParser() but acting on a ParserOutput object.
	 *
	 * @param ParserOutput $parserOutput
	 */
	static public function commitToParserOutput( ParserOutput $parserOutput ) {

		foreach ( self::$scripts as $key => $script ) {
			$parserOutput->addHeadItem( $script . "\n", $key );
		}

		foreach ( self::$headItems as $key => $item ) {
			$parserOutput->addHeadItem( "\t\t" . $item . "\n", $key );
		}

		$parserOutput->addModuleStyles( array_values( self::$resourceStyles ) );
		$parserOutput->addModules( array_values( self::$resourceModules ) );

		self::$resourceStyles = [];
		self::$resourceModules = [];
		self::$headItems = [];
	}

	/**
	 * Actually commit the collected requirements to a given OutputPage object that
	 * will later generate the HTML output. This makes sure that HTML output contains
	 * all required output items. Note that there is no parser caching at this level of
	 * processing. In particular, data should not be committed to $wgOut in methods
	 * that run during page parsing, since these would not run next time when the page
	 * is produced from parser cache.
	 *
	 * @param OutputPage $output
	 */
	static public function commitToOutputPage( OutputPage $output ) {
		foreach ( self::$scripts as $script ) {
			$output->addScript( $script );
		}
		foreach ( self::$headItems as $key => $item ) {
			$output->addHeadItem( $key, "\t\t" . $item . "\n" );
		}

		$output->addModuleStyles( array_values( self::$resourceStyles ) );
		$output->addModules( array_values( self::$resourceModules ) );

		self::$resourceStyles = [];
		self::$resourceModules = [];
		self::$headItems = [];
	}

}