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