1
|
|
|
<?php |
2
|
|
|
namespace Elgg\Assets; |
3
|
|
|
|
4
|
|
|
use ElggPriorityList; |
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* WARNING: API IN FLUX. DO NOT USE DIRECTLY. |
8
|
|
|
* |
9
|
|
|
* @access private |
10
|
|
|
* @since 1.10.0 |
11
|
|
|
*/ |
12
|
|
|
class ExternalFiles { |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* @var ElggPriorityList[] |
16
|
|
|
*/ |
17
|
|
|
protected $externals = []; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @var array |
21
|
|
|
*/ |
22
|
|
|
protected $externals_map = []; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Core registration function for external files |
26
|
|
|
* |
27
|
|
|
* @param string $type Type of external resource (js or css) |
28
|
|
|
* @param string $name Identifier used as key |
29
|
|
|
* @param string $url URL |
30
|
|
|
* @param string $location Location in the page to include the file |
31
|
|
|
* @param int $priority Loading priority of the file |
32
|
|
|
* |
33
|
|
|
* @return bool |
34
|
|
|
*/ |
35
|
38 |
|
public function register($type, $name, $url, $location, $priority = 500) { |
36
|
38 |
|
if (empty($name) || empty($url)) { |
37
|
2 |
|
return false; |
38
|
|
|
} |
39
|
|
|
|
40
|
38 |
|
$url = elgg_normalize_url($url); |
41
|
|
|
|
42
|
38 |
|
$this->setupType($type); |
43
|
|
|
|
44
|
38 |
|
$name = trim(strtolower($name)); |
45
|
|
|
|
46
|
|
|
// normalize bogus priorities, but allow empty, null, and false to be defaults. |
47
|
38 |
|
if (!is_numeric($priority)) { |
48
|
37 |
|
$priority = 500; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
// no negative priorities right now. |
52
|
38 |
|
$priority = max((int) $priority, 0); |
53
|
|
|
|
54
|
38 |
|
$item = elgg_extract($name, $this->externals_map[$type]); |
55
|
|
|
|
56
|
38 |
|
if ($item) { |
57
|
|
|
// updating a registered item |
58
|
|
|
// don't update loaded because it could already be set |
59
|
15 |
|
$item->url = $url; |
60
|
15 |
|
$item->location = $location; |
61
|
|
|
|
62
|
|
|
// if loaded before registered, that means it hasn't been added to the list yet |
63
|
15 |
|
if ($this->externals[$type]->contains($item)) { |
64
|
15 |
|
$priority = $this->externals[$type]->move($item, $priority); |
65
|
|
|
} else { |
66
|
15 |
|
$priority = $this->externals[$type]->add($item, $priority); |
67
|
|
|
} |
68
|
|
|
} else { |
69
|
|
|
$item = (object) [ |
70
|
24 |
|
'loaded' => false, |
71
|
24 |
|
'url' => $url, |
72
|
24 |
|
'location' => $location, |
73
|
|
|
]; |
74
|
24 |
|
$priority = $this->externals[$type]->add($item, $priority); |
75
|
|
|
} |
76
|
|
|
|
77
|
38 |
|
$this->externals_map[$type][$name] = $item; |
78
|
|
|
|
79
|
38 |
|
return $priority !== false; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Unregister an external file |
84
|
|
|
* |
85
|
|
|
* @param string $type Type of file: js or css |
86
|
|
|
* @param string $name The identifier of the file |
87
|
|
|
* |
88
|
|
|
* @return bool |
89
|
|
|
*/ |
90
|
2 |
|
public function unregister($type, $name) { |
91
|
2 |
|
$this->setupType($type); |
92
|
|
|
|
93
|
2 |
|
$name = trim(strtolower($name)); |
94
|
2 |
|
$item = elgg_extract($name, $this->externals_map[$type]); |
95
|
|
|
|
96
|
2 |
|
if ($item) { |
97
|
2 |
|
unset($this->externals_map[$type][$name]); |
98
|
2 |
|
return $this->externals[$type]->remove($item); |
99
|
|
|
} |
100
|
|
|
|
101
|
2 |
|
return false; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Get metadata for a registered file |
106
|
|
|
* |
107
|
|
|
* @param string $type Type of file: js or css |
108
|
|
|
* @param string $name The identifier of the file |
109
|
|
|
* |
110
|
|
|
* @return \stdClass|null |
111
|
|
|
*/ |
112
|
3 |
|
public function getFile($type, $name) { |
113
|
3 |
|
$this->setupType($type); |
114
|
|
|
|
115
|
3 |
|
$name = trim(strtolower($name)); |
116
|
3 |
|
if (!isset($this->externals_map[$type][$name])) { |
117
|
1 |
|
return null; |
118
|
|
|
} |
119
|
|
|
|
120
|
3 |
|
$item = $this->externals_map[$type][$name]; |
121
|
3 |
|
$priority = $this->externals[$type]->getPriority($item); |
122
|
|
|
|
123
|
|
|
// don't allow internal properties to be altered |
124
|
3 |
|
$clone = clone $item; |
125
|
3 |
|
$clone->priority = $priority; |
126
|
|
|
|
127
|
3 |
|
return $clone; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Load an external resource for use on this page |
132
|
|
|
* |
133
|
|
|
* @param string $type Type of file: js or css |
134
|
|
|
* @param string $name The identifier for the file |
135
|
|
|
* |
136
|
|
|
* @return void |
137
|
|
|
*/ |
138
|
25 |
|
public function load($type, $name) { |
139
|
25 |
|
$this->setupType($type); |
140
|
|
|
|
141
|
25 |
|
$name = trim(strtolower($name)); |
142
|
|
|
|
143
|
25 |
|
$item = elgg_extract($name, $this->externals_map[$type]); |
144
|
|
|
|
145
|
25 |
|
if ($item) { |
146
|
|
|
// update a registered item |
147
|
23 |
|
$item->loaded = true; |
148
|
|
|
} else { |
149
|
|
|
$item = (object) [ |
150
|
3 |
|
'loaded' => true, |
151
|
|
|
'url' => '', |
152
|
|
|
'location' => '', |
153
|
|
|
]; |
154
|
3 |
|
if (elgg_view_exists($name)) { |
155
|
|
|
$item->url = elgg_get_simplecache_url($name); |
156
|
|
|
$item->location = ($type == 'js') ? 'foot' : 'head'; |
157
|
|
|
} |
158
|
|
|
|
159
|
3 |
|
$this->externals[$type]->add($item); |
160
|
3 |
|
$this->externals_map[$type][$name] = $item; |
161
|
|
|
} |
162
|
25 |
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Get external resource descriptors |
166
|
|
|
* |
167
|
|
|
* @param string $type Type of file: js or css |
168
|
|
|
* @param string $location Page location |
169
|
|
|
* |
170
|
|
|
* @return string[] URLs of files to load |
171
|
|
|
*/ |
172
|
7 |
|
public function getLoadedFiles($type, $location) { |
173
|
7 |
|
if (!isset($this->externals[$type])) { |
174
|
1 |
|
return []; |
175
|
|
|
} |
176
|
|
|
|
177
|
7 |
|
$items = $this->externals[$type]->getElements(); |
178
|
|
|
|
179
|
7 |
|
$items = array_filter($items, function($v) use ($location) { |
180
|
7 |
|
return $v->loaded == true && $v->location == $location; |
181
|
7 |
|
}); |
182
|
7 |
|
if ($items) { |
|
|
|
|
183
|
7 |
|
array_walk($items, function(&$v, $k){ |
|
|
|
|
184
|
7 |
|
$v = $v->url; |
185
|
7 |
|
}); |
186
|
|
|
} |
187
|
7 |
|
return $items; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* Get registered file objects |
192
|
|
|
* |
193
|
|
|
* @param string $type Type of file: js or css |
194
|
|
|
* @param string $location Page location |
195
|
|
|
* |
196
|
|
|
* @return \stdClass[] |
197
|
|
|
*/ |
198
|
1 |
|
public function getRegisteredFiles($type, $location) { |
199
|
1 |
|
if (!isset($this->externals[$type])) { |
200
|
|
|
return []; |
201
|
|
|
} |
202
|
|
|
|
203
|
1 |
|
$ret = []; |
204
|
1 |
|
$items = $this->externals[$type]->getElements(); |
205
|
1 |
|
$items = array_filter($items, function($v) use ($location) { |
206
|
1 |
|
return ($v->location == $location); |
207
|
1 |
|
}); |
208
|
|
|
|
209
|
1 |
|
foreach ($items as $item) { |
210
|
1 |
|
$ret[] = clone $item; |
211
|
|
|
} |
212
|
|
|
|
213
|
1 |
|
return $ret; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Unregister all files |
218
|
|
|
* |
219
|
|
|
* @return void |
220
|
|
|
*/ |
221
|
7 |
|
public function reset() { |
222
|
7 |
|
$this->externals = []; |
223
|
7 |
|
$this->externals_map = []; |
224
|
7 |
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Bootstraps the externals data structure |
228
|
|
|
* |
229
|
|
|
* @param string $type The type of external, js or css. |
230
|
|
|
* @return void |
231
|
|
|
*/ |
232
|
41 |
|
protected function setupType($type) { |
233
|
41 |
|
if (!isset($this->externals[$type])) { |
234
|
25 |
|
$this->externals[$type] = new \ElggPriorityList(); |
235
|
|
|
} |
236
|
|
|
|
237
|
41 |
|
if (!isset($this->externals_map[$type])) { |
238
|
25 |
|
$this->externals_map[$type] = []; |
239
|
|
|
} |
240
|
41 |
|
} |
241
|
|
|
} |
242
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.