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 writer.write("\n
159 }
160 else 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("});\n
175 }
176 }
177
178 public static enum ModulesType {
179
180 AUI, ES6
181
182 }
183
184 private void _addToSBIndexList(StringBundler sb) {
185 ObjectValuePair<StringBundler, Integer> ovp = new ObjectValuePair<>(
186 sb, sb.index());
187
188 int index = _sbIndexList.indexOf(ovp);
189
190 if (index == -1) {
191 _sbIndexList.add(ovp);
192 }
193 else {
194 ovp = _sbIndexList.get(index);
195
196 ovp.setValue(sb.index());
197 }
198 }
199
200 private Map<String, String> _generateVariables(
201 Set<String> requiredFileNames) {
202
203 Map<String, Integer> indexes = new HashMap<>();
204 Set<String> generatedVariables = new HashSet<>();
205 Map<String, String> generatedVariablesMap = new HashMap<>();
206
207 for (String requiredFileName : requiredFileNames) {
208 StringBundler sb = new StringBundler();
209
210 CharSequence firstCharSequence = requiredFileName.subSequence(0, 1);
211
212 Matcher matcher = _validFirstCharacterPattern.matcher(
213 firstCharSequence);
214
215 if (!matcher.matches()) {
216 sb.append(StringPool.UNDERLINE);
217 }
218 else {
219 sb.append(firstCharSequence);
220 }
221
222 for (int i = 1; i < requiredFileName.length(); i++) {
223 CharSequence currentCharSequence = requiredFileName.subSequence(
224 i, i + 1);
225
226 matcher = _validCharactersPattern.matcher(currentCharSequence);
227
228 if (!matcher.matches()) {
229 while (++i < requiredFileName.length()) {
230 CharSequence nextCharSequence =
231 requiredFileName.subSequence(i, i + 1);
232
233 matcher = _validCharactersPattern.matcher(
234 nextCharSequence);
235
236 if (matcher.matches()) {
237 sb.append(
238 StringUtil.toUpperCase(
239 nextCharSequence.toString()));
240
241 break;
242 }
243 }
244 }
245 else {
246 sb.append(currentCharSequence);
247 }
248 }
249
250 String generatedVariable = sb.toString();
251
252 if (generatedVariables.contains(generatedVariable)) {
253 int index = 1;
254
255 if (indexes.containsKey(generatedVariable)) {
256 index = indexes.get(generatedVariable) + 1;
257 }
258
259 indexes.put(generatedVariable, index);
260
261 generatedVariable += index;
262 }
263
264 generatedVariables.add(generatedVariable);
265 generatedVariablesMap.put(requiredFileName, generatedVariable);
266 }
267
268 return generatedVariablesMap;
269 }
270
271 private PortletData _getPortletData(String portletId) {
272 if (Validator.isNull(portletId)) {
273 portletId = StringPool.BLANK;
274 }
275
276 PortletData portletData = _portletDataMap.get(portletId);
277
278 if (portletData == null) {
279 portletData = new PortletData();
280
281 PortletData oldPortletData = _portletDataMap.putIfAbsent(
282 portletId, portletData);
283
284 if (oldPortletData != null) {
285 portletData = oldPortletData;
286 }
287 }
288
289 return portletData;
290 }
291
292 private static final Pattern _validCharactersPattern = Pattern.compile(
293 "[0-9a-z_$]", Pattern.CASE_INSENSITIVE);
294 private static final Pattern _validFirstCharacterPattern = Pattern.compile(
295 "[a-z_$]", Pattern.CASE_INSENSITIVE);
296 private static final long serialVersionUID = 1L;
297
298 private final ConcurrentMap<String, PortletData> _portletDataMap =
299 new ConcurrentHashMap<>();
300 private final List<ObjectValuePair<StringBundler, Integer>> _sbIndexList =
301 new ArrayList<>();
302
303 private static class PortletData implements Serializable {
304
305 public void append(
306 String content, String modules, ModulesType modulesType) {
307
308 if (Validator.isNull(modules)) {
309 _rawSB.append(content);
310 }
311 else {
312 String[] modulesArray = StringUtil.split(modules);
313
314 if (modulesType == ModulesType.AUI) {
315 _auiCallbackSB.append("(function() {");
316 _auiCallbackSB.append(content);
317 _auiCallbackSB.append("})();");
318
319 for (String module : modulesArray) {
320 _auiModulesSet.add(StringUtil.trim(module));
321 }
322 }
323 else {
324 _es6CallbackSB.append("(function() {");
325 _es6CallbackSB.append(content);
326 _es6CallbackSB.append("})();");
327
328 for (String module : modulesArray) {
329 _es6ModulesSet.add(StringUtil.trim(module));
330 }
331 }
332 }
333 }
334
335 public void append(
336 StringBundler contentSB, String modules, ModulesType modulesType) {
337
338 if (Validator.isNull(modules)) {
339 _rawSB.append(contentSB);
340 }
341 else {
342 String[] modulesArray = StringUtil.split(modules);
343
344 if (modulesType == ModulesType.AUI) {
345 _auiCallbackSB.append("(function() {");
346 _auiCallbackSB.append(contentSB);
347 _auiCallbackSB.append("})();");
348
349 for (String module : modulesArray) {
350 _auiModulesSet.add(StringUtil.trim(module));
351 }
352 }
353 else {
354 _es6CallbackSB.append("(function() {");
355 _es6CallbackSB.append(contentSB);
356 _es6CallbackSB.append("})();");
357
358 for (String module : modulesArray) {
359 _es6ModulesSet.add(StringUtil.trim(module));
360 }
361 }
362 }
363 }
364
365 private static final long serialVersionUID = 1L;
366
367 private final StringBundler _auiCallbackSB = new StringBundler();
368 private final Set<String> _auiModulesSet = new HashSet<>();
369 private final StringBundler _es6CallbackSB = new StringBundler();
370 private final Set<String> _es6ModulesSet = new HashSet<>();
371 private final StringBundler _rawSB = new StringBundler();
372
373 }
374
375 }