1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Botble\Assets; |
4
|
|
|
|
5
|
|
|
use Collective\Html\HtmlBuilder; |
6
|
|
|
use Illuminate\Config\Repository; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Class Assets |
10
|
|
|
* @package Botble\Assets |
11
|
|
|
* @author Sang Nguyen |
12
|
|
|
* @since 22/07/2015 11:23 PM |
13
|
|
|
*/ |
14
|
|
|
class Assets |
15
|
|
|
{ |
16
|
|
|
/** |
17
|
|
|
* @var Repository |
18
|
|
|
*/ |
19
|
|
|
protected $config; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var HtmlBuilder |
23
|
|
|
*/ |
24
|
|
|
protected $htmlBuilder; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var array |
28
|
|
|
*/ |
29
|
|
|
protected $scripts = []; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var array |
33
|
|
|
*/ |
34
|
|
|
protected $styles = []; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var array |
38
|
|
|
*/ |
39
|
|
|
protected $appendedScripts = [ |
40
|
|
|
'header' => [], |
41
|
|
|
'footer' => [], |
42
|
|
|
]; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var array |
46
|
|
|
*/ |
47
|
|
|
protected $appendedStyles = []; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var string |
51
|
|
|
*/ |
52
|
|
|
protected $build = ''; |
53
|
|
|
|
54
|
|
|
const ASSETS_SCRIPT_POSITION_HEADER = 'header'; |
55
|
|
|
const ASSETS_SCRIPT_POSITION_FOOTER = 'footer'; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Assets constructor. |
59
|
|
|
* @author Sang Nguyen |
60
|
|
|
* @param Repository $config |
61
|
|
|
* @param HtmlBuilder $htmlBuilder |
62
|
|
|
*/ |
63
|
|
|
public function __construct(Repository $config, HtmlBuilder $htmlBuilder) |
64
|
|
|
{ |
65
|
|
|
$this->config = $config->get('assets'); |
66
|
|
|
$this->htmlBuilder = $htmlBuilder; |
67
|
|
|
|
68
|
|
|
$this->scripts = $this->config['scripts']; |
69
|
|
|
$this->styles = $this->config['styles']; |
70
|
|
|
|
71
|
|
|
$this->build = $this->config['enable_version'] ? '?v=' . $this->config['version'] : ''; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Add Javascript to current module |
76
|
|
|
* |
77
|
|
|
* @param array $assets |
78
|
|
|
* @return $this |
79
|
|
|
* @author Sang Nguyen |
80
|
|
|
*/ |
81
|
|
|
public function addScripts($assets) |
82
|
|
|
{ |
83
|
|
|
if (!is_array($assets)) { |
84
|
|
|
$assets = [$assets]; |
85
|
|
|
} |
86
|
|
|
$this->scripts = array_merge($this->scripts, $assets); |
87
|
|
|
return $this; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Add Css to current module |
92
|
|
|
* |
93
|
|
|
* @param array $assets |
94
|
|
|
* @return $this |
95
|
|
|
* @author Sang Nguyen |
96
|
|
|
*/ |
97
|
|
|
public function addStyles($assets) |
98
|
|
|
{ |
99
|
|
|
if (!is_array($assets)) { |
100
|
|
|
$assets = [$assets]; |
101
|
|
|
} |
102
|
|
|
$this->styles = array_merge($this->styles, $assets); |
103
|
|
|
return $this; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* @param $assets |
108
|
|
|
* @return $this |
109
|
|
|
* @author Sang Nguyen |
110
|
|
|
*/ |
111
|
|
|
public function addStylesDirectly($assets) |
112
|
|
|
{ |
113
|
|
|
if (!is_array($assets)) { |
114
|
|
|
$assets = func_get_args(); |
115
|
|
|
} |
116
|
|
View Code Duplication |
foreach ($assets as &$item) { |
|
|
|
|
117
|
|
|
$item = $item . $this->build; |
118
|
|
|
if (!in_array($item, $this->appendedStyles)) { |
119
|
|
|
$this->appendedStyles[] = [ |
120
|
|
|
'src' => $item, |
121
|
|
|
'attributes' => [], |
122
|
|
|
]; |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
return $this; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* @param $assets |
130
|
|
|
* @param string $location |
131
|
|
|
* @return $this |
132
|
|
|
* @author Sang Nguyen |
133
|
|
|
*/ |
134
|
|
|
public function addScriptsDirectly($assets, $location = self::ASSETS_SCRIPT_POSITION_FOOTER) |
135
|
|
|
{ |
136
|
|
|
if (!is_array($assets)) { |
137
|
|
|
$assets = func_get_args(); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
View Code Duplication |
foreach ($assets as &$item) { |
|
|
|
|
141
|
|
|
$item = $item . $this->build; |
142
|
|
|
if (!in_array($item, $this->appendedScripts[$location])) { |
143
|
|
|
$this->appendedScripts[$location][] = [ |
144
|
|
|
'src' => $item, |
145
|
|
|
'attributes' => [], |
146
|
|
|
]; |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
return $this; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Remove Css to current module |
154
|
|
|
* |
155
|
|
|
* @param array $assets |
156
|
|
|
* @return $this |
157
|
|
|
* @author Sang Nguyen |
158
|
|
|
*/ |
159
|
|
View Code Duplication |
public function removeStyles($assets) |
|
|
|
|
160
|
|
|
{ |
161
|
|
|
if (!is_array($assets)) { |
162
|
|
|
$assets = [$assets]; |
163
|
|
|
} |
164
|
|
|
foreach ($assets as $rem) { |
165
|
|
|
unset($this->styles[array_search($rem, $this->styles)]); |
166
|
|
|
} |
167
|
|
|
return $this; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Add Javascript |
172
|
|
|
* |
173
|
|
|
* @param array $assets |
174
|
|
|
* @return $this |
175
|
|
|
* @author Sang Nguyen |
176
|
|
|
*/ |
177
|
|
View Code Duplication |
public function removeScripts($assets) |
|
|
|
|
178
|
|
|
{ |
179
|
|
|
if (!is_array($assets)) { |
180
|
|
|
$assets = [$assets]; |
181
|
|
|
} |
182
|
|
|
foreach ($assets as $rem) { |
183
|
|
|
unset($this->scripts[array_search($rem, $this->scripts)]); |
184
|
|
|
} |
185
|
|
|
return $this; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Get All Javascript in current module |
190
|
|
|
* |
191
|
|
|
* @param string $location : top or bottom |
192
|
|
|
* @return array |
193
|
|
|
* @author Sang Nguyen |
194
|
|
|
*/ |
195
|
|
|
public function getScripts($location = null) |
196
|
|
|
{ |
197
|
|
|
$scripts = []; |
198
|
|
|
$this->scripts = array_unique($this->scripts); |
199
|
|
|
foreach ($this->scripts as $script) { |
200
|
|
|
$configName = 'resources.javascript.' . $script; |
201
|
|
|
|
202
|
|
|
if (isset($this->config[$configName])) { |
203
|
|
|
if (!empty($location) && $location != $this->config[$configName . '.location']) { |
204
|
|
|
continue; // Skip assets that don't match this location |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
$scripts = array_merge($scripts, $this->getScriptItem($location, $configName, $script)); |
208
|
|
|
} |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
if (isset($this->appendedScripts[$location])) { |
212
|
|
|
$scripts = array_merge($scripts, $this->appendedScripts[$location]); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
return $scripts; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Get All CSS in current module |
220
|
|
|
* |
221
|
|
|
* @param array $lastModules : append last CSS to current module |
222
|
|
|
* @return array |
223
|
|
|
* @author Sang Nguyen |
224
|
|
|
*/ |
225
|
|
|
public function getStyles($lastModules = []) |
226
|
|
|
{ |
227
|
|
|
$stylesheets = []; |
228
|
|
|
if (!empty($lastModules)) { |
229
|
|
|
$this->styles = array_merge($this->styles, $lastModules); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
$this->styles = array_unique($this->styles); |
233
|
|
|
foreach ($this->styles as $style) { |
234
|
|
|
$configName = 'resources.stylesheets.' . $style; |
235
|
|
|
if (isset($this->config[$configName])) { |
236
|
|
|
$src = $this->config[$configName . '.src.local']; |
237
|
|
|
$attributes = $this->config[$configName . '.attributes'] ?? []; |
238
|
|
View Code Duplication |
if ($this->config[$configName . '.use_cdn'] && !$this->config['offline']) { |
|
|
|
|
239
|
|
|
$src = $this->config[$configName . '.src.cdn']; |
240
|
|
|
$attributes = []; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
foreach ((array)$src as $s) { |
244
|
|
|
$stylesheets[] = [ |
245
|
|
|
'src' => $s . $this->build, |
246
|
|
|
'attributes' => $attributes, |
247
|
|
|
]; |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
return array_merge($stylesheets, $this->appendedStyles); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* @param $name |
257
|
|
|
* @author Sang Nguyen |
258
|
|
|
*/ |
259
|
|
|
public function scriptToHtml($name) |
260
|
|
|
{ |
261
|
|
|
return $this->itemToHtml($name, 'script'); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* @param $name |
266
|
|
|
* @author Sang Nguyen |
267
|
|
|
*/ |
268
|
|
|
public function styleToHtml($name) |
269
|
|
|
{ |
270
|
|
|
return $this->itemToHtml($name, 'style'); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* @return string |
275
|
|
|
* @throws \Throwable |
276
|
|
|
* @author Sang Nguyen |
277
|
|
|
*/ |
278
|
|
|
public function renderHeader() |
279
|
|
|
{ |
280
|
|
|
$stylesheets = $this->getStyles(['core']); |
281
|
|
|
$headScripts = $this->getScripts(self::ASSETS_SCRIPT_POSITION_HEADER); |
282
|
|
|
return view('assets::header', compact('stylesheets', 'headScripts'))->render(); |
|
|
|
|
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* @return string |
287
|
|
|
* @throws \Throwable |
288
|
|
|
* @author Sang Nguyen |
289
|
|
|
*/ |
290
|
|
|
public function renderFooter() |
291
|
|
|
{ |
292
|
|
|
$bodyScripts = $this->getScripts(self::ASSETS_SCRIPT_POSITION_FOOTER); |
293
|
|
|
return view('assets::footer', compact('bodyScripts'))->render(); |
|
|
|
|
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* @param $location |
298
|
|
|
* @param $configName |
299
|
|
|
* @param $script |
300
|
|
|
* @return array |
301
|
|
|
*/ |
302
|
|
|
protected function getScriptItem($location, $configName, $script) |
303
|
|
|
{ |
304
|
|
|
$scripts = []; |
305
|
|
|
$src = $this->config[$configName . '.src.local']; |
306
|
|
|
$cdn = false; |
307
|
|
|
$attributes = $this->config[$configName . '.attributes'] ?? []; |
308
|
|
|
|
309
|
|
View Code Duplication |
if ($this->config[$configName . '.use_cdn'] && !$this->config['offline']) { |
|
|
|
|
310
|
|
|
$src = $this->config[$configName . '.src.cdn']; |
311
|
|
|
$cdn = true; |
312
|
|
|
$attributes = []; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
if ($this->config[$configName . '.include_style']) { |
316
|
|
|
$this->addStyles([$script]); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
if (!is_array($src)) { |
320
|
|
|
$scripts[] = ['src' => $src . $this->build, 'attributes' => $attributes]; |
321
|
|
|
} else { |
322
|
|
|
foreach ($src as $s) { |
323
|
|
|
$scripts[] = ['src' => $s . $this->build, 'attributes' => $attributes]; |
324
|
|
|
} |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
if (empty($src) && |
328
|
|
|
$cdn && $location === self::ASSETS_SCRIPT_POSITION_HEADER && |
329
|
|
|
isset($this->config[$configName . '.fallback']) |
330
|
|
|
) { |
331
|
|
|
$scripts[] = $this->getFallbackScript($src, $configName); |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
return $scripts; |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* Fallback to local script if CDN fails |
339
|
|
|
* @param $src |
340
|
|
|
* @param $configName |
341
|
|
|
* @return array |
342
|
|
|
*/ |
343
|
|
|
protected function getFallbackScript($src, $configName) |
344
|
|
|
{ |
345
|
|
|
return [ |
346
|
|
|
'src' => $src, |
347
|
|
|
'fallback' => $this->config[$configName . '.fallback'], |
348
|
|
|
'fallbackURL' => $this->config[$configName . '.src.local'], |
349
|
|
|
]; |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* @param $name |
354
|
|
|
* @param string $type |
355
|
|
|
* @return null|string |
356
|
|
|
*/ |
357
|
|
|
protected function itemToHtml($name, $type = 'style') |
358
|
|
|
{ |
359
|
|
|
if (!in_array($type, ['style', 'script'])) { |
360
|
|
|
return null; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
$config = 'resources.stylesheets.' . $name; |
364
|
|
|
if ($type === 'script') { |
365
|
|
|
$config = 'resources.javascript.' . $name; |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
if (isset($this->config[$config])) { |
369
|
|
|
|
370
|
|
|
$src = $this->config[$config . '.src.local']; |
371
|
|
View Code Duplication |
if ($this->config[$config . '.use_cdn'] && !$this->config['offline']) { |
|
|
|
|
372
|
|
|
$src = $this->config[$config . '.src.cdn']; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
if (!is_array($src)) { |
376
|
|
|
$src = [$src]; |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
$html = ''; |
380
|
|
|
foreach ($src as $item) { |
381
|
|
|
$html .= $this->htmlBuilder->{$type}($item . $this->build, ['class' => 'hidden'])->toHtml(); |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
return $html; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
return null; |
388
|
|
|
} |
389
|
|
|
} |
390
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.