001
014
015 package com.liferay.portal.kernel.servlet.taglib.aui;
016
017 import com.liferay.portal.kernel.util.Mergeable;
018 import com.liferay.portal.kernel.util.ObjectValuePair;
019 import com.liferay.portal.kernel.util.StringBundler;
020 import com.liferay.portal.kernel.util.StringPool;
021 import com.liferay.portal.kernel.util.StringUtil;
022 import com.liferay.portal.kernel.util.Validator;
023
024 import java.io.IOException;
025 import java.io.Serializable;
026 import java.io.Writer;
027
028 import java.util.ArrayList;
029 import java.util.HashMap;
030 import java.util.HashSet;
031 import java.util.Iterator;
032 import java.util.List;
033 import java.util.Map;
034 import java.util.Set;
035 import java.util.concurrent.ConcurrentHashMap;
036 import java.util.concurrent.ConcurrentMap;
037 import java.util.regex.Matcher;
038 import java.util.regex.Pattern;
039
040 import javax.servlet.http.HttpServletRequest;
041
042
046 public class ScriptData implements Mergeable<ScriptData>, Serializable {
047
048 public void append(
049 String portletId, String content, String modules,
050 ModulesType modulesType) {
051
052 PortletData portletData = _getPortletData(portletId);
053
054 portletData.append(content, modules, modulesType);
055 }
056
057 public void append(
058 String portletId, StringBundler contentSB, String modules,
059 ModulesType modulesType) {
060
061 PortletData portletData = _getPortletData(portletId);
062
063 portletData.append(contentSB, modules, modulesType);
064 }
065
066 public void mark() {
067 for (PortletData portletData : _portletDataMap.values()) {
068 _addToSBIndexList(portletData._auiCallbackSB);
069 _addToSBIndexList(portletData._es6CallbackSB);
070 _addToSBIndexList(portletData._rawSB);
071 }
072 }
073
074 @Override
075 public ScriptData merge(ScriptData scriptData) {
076 if ((scriptData != null) && (scriptData != this)) {
077 _portletDataMap.putAll(scriptData._portletDataMap);
078 }
079
080 return this;
081 }
082
083 public void reset() {
084 for (ObjectValuePair<StringBundler, Integer> ovp : _sbIndexList) {
085 StringBundler sb = ovp.getKey();
086
087 sb.setIndex(ovp.getValue());
088 }
089 }
090
091 public void writeTo(HttpServletRequest request, Writer writer)
092 throws IOException {
093
094 writer.write("<script type=\"text/javascript\">\n
095
096 StringBundler auiModulesSB = new StringBundler(_portletDataMap.size());
097 Set<String> auiModulesSet = new HashSet<>();
098 StringBundler es6ModulesSB = new StringBundler(_portletDataMap.size());
099 Set<String> es6ModulesSet = new HashSet<>();
100
101 for (PortletData portletData : _portletDataMap.values()) {
102 portletData._rawSB.writeTo(writer);
103
104 if (!portletData._auiModulesSet.isEmpty()) {
105 auiModulesSB.append(portletData._auiCallbackSB);
106 }
107
108 if (!portletData._es6ModulesSet.isEmpty()) {
109 es6ModulesSB.append(portletData._es6CallbackSB);
110 }
111
112 auiModulesSet.addAll(portletData._auiModulesSet);
113 es6ModulesSet.addAll(portletData._es6ModulesSet);
114 }
115
116 if ((auiModulesSB.index() == 0) && (es6ModulesSB.index() == 0)) {
117 writer.write("\n
118
119 return;
120 }
121
122 if (!es6ModulesSet.isEmpty()) {
123 writer.write("require(");
124
125 Map<String, String> generatedVariables = _generateVariables(
126 es6ModulesSet);
127
128 Iterator<String> iterator = es6ModulesSet.iterator();
129
130 while (iterator.hasNext()) {
131 writer.write(StringPool.APOSTROPHE);
132 writer.write(iterator.next());
133 writer.write(StringPool.APOSTROPHE);
134
135 if (iterator.hasNext()) {
136 writer.write(StringPool.COMMA_AND_SPACE);
137 }
138 }
139
140 writer.write(StringPool.COMMA_AND_SPACE);
141 writer.write("function(");
142
143 iterator = es6ModulesSet.iterator();
144
145 while (iterator.hasNext()) {
146 writer.write(generatedVariables.get(iterator.next()));
147
148 if (iterator.hasNext()) {
149 writer.write(StringPool.COMMA_AND_SPACE);
150 }
151 }
152
153 writer.write(") {\n");
154
155 es6ModulesSB.writeTo(writer);
156
157 writer.write("},\nfunction(error) {\nconsole.error(error);\n});");
158 }
159
160 if (!auiModulesSet.isEmpty()) {
161 writer.write("AUI().use(");
162
163 for (String use : auiModulesSet) {
164 writer.write(StringPool.APOSTROPHE);
165 writer.write(use);
166 writer.write(StringPool.APOSTROPHE);
167 writer.write(StringPool.COMMA_AND_SPACE);
168 }
169
170 writer.write("function(A) {");
171
172 auiModulesSB.writeTo(writer);
173
174 writer.write("});");
175 }
176
177 writer.write("\n
178 }
179
180 public static enum ModulesType {
181
182 AUI, ES6
183
184 }
185
186 private void _addToSBIndexList(StringBundler sb) {
187 ObjectValuePair<StringBundler, Integer> ovp = new ObjectValuePair<>(
188 sb, sb.index());
189
190 int index = _sbIndexList.indexOf(ovp);
191
192 if (index == -1) {
193 _sbIndexList.add(ovp);
194 }
195 else {
196 ovp = _sbIndexList.get(index);
197
198 ovp.setValue(sb.index());
199 }
200 }
201
202 private Map<String, String> _generateVariables(
203 Set<String> requiredFileNames) {
204
205 Map<String, Integer> indexes = new HashMap<>();
206 Set<String> generatedVariables = new HashSet<>();
207 Map<String, String> generatedVariablesMap = new HashMap<>();
208
209 for (String requiredFileName : requiredFileNames) {
210 StringBundler sb = new StringBundler();
211
212 CharSequence firstCharSequence = requiredFileName.subSequence(0, 1);
213
214 Matcher matcher = _validFirstCharacterPattern.matcher(
215 firstCharSequence);
216
217 if (!matcher.matches()) {
218 sb.append(StringPool.UNDERLINE);
219 }
220 else {
221 sb.append(firstCharSequence);
222 }
223
224 for (int i = 1; i < requiredFileName.length(); i++) {
225 CharSequence currentCharSequence = requiredFileName.subSequence(
226 i, i + 1);
227
228 matcher = _validCharactersPattern.matcher(currentCharSequence);
229
230 if (!matcher.matches()) {
231 while (++i < requiredFileName.length()) {
232 CharSequence nextCharSequence =
233 requiredFileName.subSequence(i, i + 1);
234
235 matcher = _validCharactersPattern.matcher(
236 nextCharSequence);
237
238 if (matcher.matches()) {
239 sb.append(
240 StringUtil.toUpperCase(
241 nextCharSequence.toString()));
242
243 break;
244 }
245 }
246 }
247 else {
248 sb.append(currentCharSequence);
249 }
250 }
251
252 String generatedVariable = sb.toString();
253
254 if (generatedVariables.contains(generatedVariable)) {
255 int index = 1;
256
257 if (indexes.containsKey(generatedVariable)) {
258 index = indexes.get(generatedVariable) + 1;
259 }
260
261 indexes.put(generatedVariable, index);
262
263 generatedVariable += index;
264 }
265
266 generatedVariables.add(generatedVariable);
267 generatedVariablesMap.put(requiredFileName, generatedVariable);
268 }
269
270 return generatedVariablesMap;
271 }
272
273 private PortletData _getPortletData(String portletId) {
274 if (Validator.isNull(portletId)) {
275 portletId = StringPool.BLANK;
276 }
277
278 PortletData portletData = _portletDataMap.get(portletId);
279
280 if (portletData == null) {
281 portletData = new PortletData();
282
283 PortletData oldPortletData = _portletDataMap.putIfAbsent(
284 portletId, portletData);
285
286 if (oldPortletData != null) {
287 portletData = oldPortletData;
288 }
289 }
290
291 return portletData;
292 }
293
294 private static final Pattern _validCharactersPattern = Pattern.compile(
295 "[0-9a-z_$]", Pattern.CASE_INSENSITIVE);
296 private static final Pattern _validFirstCharacterPattern = Pattern.compile(
297 "[a-z_$]", Pattern.CASE_INSENSITIVE);
298 private static final long serialVersionUID = 1L;
299
300 private final ConcurrentMap<String, PortletData> _portletDataMap =
301 new ConcurrentHashMap<>();
302 private final List<ObjectValuePair<StringBundler, Integer>> _sbIndexList =
303 new ArrayList<>();
304
305 private static class PortletData implements Serializable {
306
307 public void append(
308 String content, String modules, ModulesType modulesType) {
309
310 if (Validator.isNull(modules)) {
311 _rawSB.append(content);
312 }
313 else {
314 String[] modulesArray = StringUtil.split(modules);
315
316 if (modulesType == ModulesType.AUI) {
317 _auiCallbackSB.append("(function() {");
318 _auiCallbackSB.append(content);
319 _auiCallbackSB.append("})();");
320
321 for (String module : modulesArray) {
322 _auiModulesSet.add(StringUtil.trim(module));
323 }
324 }
325 else {
326 _es6CallbackSB.append("(function() {");
327 _es6CallbackSB.append(content);
328 _es6CallbackSB.append("})();");
329
330 for (String module : modulesArray) {
331 _es6ModulesSet.add(StringUtil.trim(module));
332 }
333 }
334 }
335 }
336
337 public void append(
338 StringBundler contentSB, String modules, ModulesType modulesType) {
339
340 if (Validator.isNull(modules)) {
341 _rawSB.append(contentSB);
342 }
343 else {
344 String[] modulesArray = StringUtil.split(modules);
345
346 if (modulesType == ModulesType.AUI) {
347 _auiCallbackSB.append("(function() {");
348 _auiCallbackSB.append(contentSB);
349 _auiCallbackSB.append("})();");
350
351 for (String module : modulesArray) {
352 _auiModulesSet.add(StringUtil.trim(module));
353 }
354 }
355 else {
356 _es6CallbackSB.append("(function() {");
357 _es6CallbackSB.append(contentSB);
358 _es6CallbackSB.append("})();");
359
360 for (String module : modulesArray) {
361 _es6ModulesSet.add(StringUtil.trim(module));
362 }
363 }
364 }
365 }
366
367 private static final long serialVersionUID = 1L;
368
369 private final StringBundler _auiCallbackSB = new StringBundler();
370 private final Set<String> _auiModulesSet = new HashSet<>();
371 private final StringBundler _es6CallbackSB = new StringBundler();
372 private final Set<String> _es6ModulesSet = new HashSet<>();
373 private final StringBundler _rawSB = new StringBundler();
374
375 }
376
377 }