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
|
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\ResourceLoader;
use Wikimedia\Minify\CSSMin;
// Per https://phabricator.wikimedia.org/T241091
// phpcs:disable MediaWiki.Commenting.FunctionAnnotations.UnrecognizedAnnotation
/**
* Module augmented with context-specific LESS variables.
*
* @ingroup ResourceLoader
* @since 1.32
*/
class LessVarFileModule extends FileModule {
protected $lessVariables = [];
/**
* @inheritDoc
*/
public function __construct(
array $options = [],
$localBasePath = null,
$remoteBasePath = null
) {
if ( isset( $options['lessMessages'] ) ) {
$this->lessVariables = $options['lessMessages'];
}
parent::__construct( $options, $localBasePath, $remoteBasePath );
}
/**
* @inheritDoc
*/
public function getMessages() {
// Overload so MessageBlobStore can detect updates to messages and purge as needed.
return array_merge( $this->messages, $this->lessVariables );
}
/**
* Return a subset of messages from a JSON string representation.
*
* @param string|null $blob JSON, or null if module has no declared messages
* @param string[] $allowed
* @return array
*/
private function pluckFromMessageBlob( $blob, array $allowed ): array {
$data = $blob ? json_decode( $blob, true ) : [];
// Keep only the messages intended for LESS export
// (opposite of getMessages essentially).
return array_intersect_key( $data, array_fill_keys( $allowed, true ) );
}
/**
* @inheritDoc
*/
protected function getMessageBlob( Context $context ) {
$blob = parent::getMessageBlob( $context );
if ( !$blob ) {
// If module has no blob, preserve null to avoid needless WAN cache allocation
// client output for modules without messages.
return $blob;
}
return json_encode( (object)$this->pluckFromMessageBlob( $blob, $this->messages ) );
}
// phpcs:disable MediaWiki.Commenting.DocComment.SpacingDocTag, Squiz.WhiteSpace.FunctionSpacing.Before
/**
* Escape and wrap a message value as literal string for LESS.
*
* This mostly lets CSSMin escape it and wrap it, but also escape single quotes
* for compatibility with LESS's feature of variable interpolation into other strings.
* This is relatively rare for most use of LESS, but for messages it is quite common.
*
* Example:
*
* @code
* @x: "foo's";
* .eg { content: 'Value is @{x}'; }
* @endcode
*
* Produces output: `.eg { content: 'Value is foo's'; }`.
* (Tested in less.php 1.8.1, and Less.js 2.7)
*
* @param string $msg
* @return string wrapped LESS variable value
*/
private static function wrapAndEscapeMessage( $msg ) {
return str_replace( "'", "\'", CSSMin::serializeStringValue( $msg ) );
}
// phpcs:enable MediaWiki.Commenting.DocComment.SpacingDocTag, Squiz.WhiteSpace.FunctionSpacing.Before
/**
* Get language-specific LESS variables for this module.
*
* @param Context $context
* @return array LESS variables
*/
protected function getLessVars( Context $context ) {
$vars = parent::getLessVars( $context );
$blob = parent::getMessageBlob( $context );
$messages = $this->pluckFromMessageBlob( $blob, $this->lessVariables );
// It is important that we iterate the declared list from $this->lessVariables,
// and not $messages since in the case of undefined messages, the key is
// omitted entirely from the blob. This emits a log warning for developers,
// but we must still carry on and produce a valid LESS variable declaration,
// to avoid a LESS syntax error (T267785).
foreach ( $this->lessVariables as $msgKey ) {
$vars['msg-' . $msgKey] = self::wrapAndEscapeMessage( $messages[$msgKey] ?? "⧼${msgKey}⧽" );
}
return $vars;
}
}
/** @deprecated since 1.39 */
class_alias( LessVarFileModule::class, 'ResourceLoaderLessVarFileModule' );
|