@@ -95,7 +95,7 @@ public function render(string|array $entryPoint, array $attributes = []): string
95
95
$ this ->addWebLinkPreloads ($ request , $ cssLinks );
96
96
}
97
97
98
- $ scriptAttributes = $ this ->createAttributesString ($ attributes );
98
+ $ scriptAttributes = $ attributes || $ this ->scriptAttributes ? ' ' . $ this -> createAttributesString ($ attributes ) : '' ;
99
99
$ importMapJson = json_encode (['imports ' => $ importMap ], \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG );
100
100
$ output .= <<<HTML
101
101
@@ -114,21 +114,26 @@ public function render(string|array $entryPoint, array $attributes = []): string
114
114
}
115
115
116
116
if ($ polyfillPath ) {
117
- $ url = $ this ->escapeAttributeValue ($ polyfillPath );
118
- $ polyfillAttributes = $ scriptAttributes ;
117
+ $ polyfillAttributes = $ attributes + $ this ->scriptAttributes ;
119
118
120
119
// Add security attributes for the default polyfill hosted on jspm.io
121
120
if (self ::DEFAULT_ES_MODULE_SHIMS_POLYFILL_URL === $ polyfillPath ) {
122
- $ polyfillAttributes = $ this -> createAttributesString ( [
121
+ $ polyfillAttributes = [
123
122
'crossorigin ' => 'anonymous ' ,
124
123
'integrity ' => self ::DEFAULT_ES_MODULE_SHIMS_POLYFILL_INTEGRITY ,
125
- ] + $ attributes ) ;
124
+ ] + $ polyfillAttributes ;
126
125
}
127
126
128
127
$ output .= <<<HTML
129
-
130
- <!-- ES Module Shims: Import maps polyfill for modules browsers without import maps support -->
131
- <script async src=" $ url" $ polyfillAttributes></script>
128
+ <script async $ scriptAttributes>
129
+ if (!HTMLScriptElement.supports || !HTMLScriptElement.supports('importmap')) (function () {
130
+ const script = document.createElement('script');
131
+ script.src = ' {$ this ->escapeAttributeValue ($ polyfillPath , \ENT_NOQUOTES )}';
132
+ script.setAttribute('async', 'async');
133
+ {$ this ->createAttributesString ($ polyfillAttributes , "script.setAttribute('%s', '%s'); " , "\n " , \ENT_NOQUOTES )}
134
+ document.head.appendChild(script);
135
+ })();
136
+ </script>
132
137
HTML ;
133
138
}
134
139
@@ -151,12 +156,14 @@ public function render(string|array $entryPoint, array $attributes = []): string
151
156
return $ output ;
152
157
}
153
158
154
- private function escapeAttributeValue (string $ value ): string
159
+ private function escapeAttributeValue (string $ value, int $ flags = \ ENT_COMPAT | \ ENT_SUBSTITUTE ): string
155
160
{
156
- return htmlspecialchars ($ value , \ENT_COMPAT | \ENT_SUBSTITUTE , $ this ->charset );
161
+ $ value = htmlspecialchars ($ value , $ flags , $ this ->charset );
162
+
163
+ return \ENT_NOQUOTES & $ flags ? addslashes ($ value ) : $ value ;
157
164
}
158
165
159
- private function createAttributesString (array $ attributes ): string
166
+ private function createAttributesString (array $ attributes, string $ pattern = ' %s="%s" ' , string $ glue = ' ' , int $ flags = \ ENT_COMPAT | \ ENT_SUBSTITUTE ): string
160
167
{
161
168
$ attributeString = '' ;
162
169
@@ -166,15 +173,17 @@ private function createAttributesString(array $attributes): string
166
173
}
167
174
168
175
foreach ($ attributes as $ name => $ value ) {
169
- $ attributeString .= ' ' ;
176
+ if ('' !== $ attributeString ) {
177
+ $ attributeString .= $ glue ;
178
+ }
170
179
if (true === $ value ) {
171
- $ attributeString .= $ name ;
172
-
173
- continue ;
180
+ $ value = $ name ;
174
181
}
175
- $ attributeString .= \sprintf (' %s="%s" ' , $ name , $ this ->escapeAttributeValue ($ value ));
182
+ $ attributeString .= \sprintf ($ pattern , $ this -> escapeAttributeValue ( $ name , $ flags ), $ this ->escapeAttributeValue ($ value, $ flags ));
176
183
}
177
184
185
+ $ attributeString = preg_replace ('/\b([^ =]++)="\1"/ ' , '\1 ' , $ attributeString );
186
+
178
187
return $ attributeString ;
179
188
}
180
189
0 commit comments