001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.servlet.taglib.aui;
016    
017    import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
018    import com.liferay.portal.kernel.util.Mergeable;
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.HashMap;
029    import java.util.Map;
030    import java.util.Set;
031    import java.util.TreeSet;
032    import java.util.concurrent.ConcurrentHashMap;
033    import java.util.concurrent.ConcurrentMap;
034    
035    import javax.servlet.http.HttpServletRequest;
036    
037    /**
038     * @author Brian Wing Shun Chan
039     * @author Shuyang Zhou
040     */
041    public class ScriptData implements Mergeable<ScriptData>, Serializable {
042    
043            public void append(String portletId, String content, String use) {
044                    PortletData portletData = _getPortletData(portletId);
045    
046                    portletData.append(content, use);
047            }
048    
049            public void append(String portletId, StringBundler contentSB, String use) {
050                    PortletData portletData = _getPortletData(portletId);
051    
052                    portletData.append(contentSB, use);
053            }
054    
055            public void mark() {
056                    for (PortletData portletData : _portletDataMap.values()) {
057                            StringBundler callbackSB = portletData._callbackSB;
058    
059                            _sbIndexMap.put(callbackSB, callbackSB.index());
060    
061                            StringBundler rawSB = portletData._rawSB;
062    
063                            _sbIndexMap.put(rawSB, rawSB.index());
064                    }
065            }
066    
067            @Override
068            public ScriptData merge(ScriptData scriptData) {
069                    if ((scriptData != null) && (scriptData != this)) {
070                            _portletDataMap.putAll(scriptData._portletDataMap);
071                    }
072    
073                    return this;
074            }
075    
076            public void reset() {
077                    for (Map.Entry<StringBundler, Integer> entry : _sbIndexMap.entrySet()) {
078                            StringBundler sb = entry.getKey();
079    
080                            sb.setIndex(entry.getValue());
081                    }
082            }
083    
084            public void writeTo(HttpServletRequest request, Writer writer)
085                    throws IOException {
086    
087                    writer.write("<script type=\"text/javascript\">\n// <![CDATA[\n");
088    
089                    StringBundler callbackSB = new StringBundler();
090    
091                    for (PortletData portletData : _portletDataMap.values()) {
092                            portletData._rawSB.writeTo(writer);
093    
094                            callbackSB.append(portletData._callbackSB);
095                    }
096    
097                    if (callbackSB.index() == 0) {
098                            writer.write("\n// ]]>\n</script>");
099    
100                            return;
101                    }
102    
103                    String loadMethod = "use";
104    
105                    if (BrowserSnifferUtil.isIe(request) &&
106                            (BrowserSnifferUtil.getMajorVersion(request) < 8)) {
107    
108                            loadMethod = "ready";
109                    }
110    
111                    writer.write("AUI().");
112                    writer.write(loadMethod);
113                    writer.write("(");
114    
115                    Set<String> useSet = new TreeSet<String>();
116    
117                    for (PortletData portletData : _portletDataMap.values()) {
118                            useSet.addAll(portletData._useSet);
119                    }
120    
121                    for (String use : useSet) {
122                            writer.write(StringPool.APOSTROPHE);
123                            writer.write(use);
124                            writer.write(StringPool.APOSTROPHE);
125                            writer.write(StringPool.COMMA_AND_SPACE);
126                    }
127    
128                    writer.write("function(A) {");
129    
130                    callbackSB.writeTo(writer);
131    
132                    writer.write("});");
133    
134                    writer.write("\n// ]]>\n</script>");
135            }
136    
137            private PortletData _getPortletData(String portletId) {
138                    if (Validator.isNull(portletId)) {
139                            portletId = StringPool.BLANK;
140                    }
141    
142                    PortletData portletData = _portletDataMap.get(portletId);
143    
144                    if (portletData == null) {
145                            portletData = new PortletData();
146    
147                            PortletData oldPortletData = _portletDataMap.putIfAbsent(
148                                    portletId, portletData);
149    
150                            if (oldPortletData != null) {
151                                    portletData = oldPortletData;
152                            }
153                    }
154    
155                    return portletData;
156            }
157    
158            private static final long serialVersionUID = 1L;
159    
160            private ConcurrentMap<String, PortletData> _portletDataMap =
161                    new ConcurrentHashMap<String, PortletData>();
162            private Map<StringBundler, Integer> _sbIndexMap =
163                    new HashMap<StringBundler, Integer>();
164    
165            private class PortletData implements Serializable {
166    
167                    public void append(String content, String use) {
168                            if (Validator.isNull(use)) {
169                                    _rawSB.append(content);
170                            }
171                            else {
172                                    _callbackSB.append("(function() {");
173                                    _callbackSB.append(content);
174                                    _callbackSB.append("})();");
175    
176                                    String[] useArray = StringUtil.split(use);
177    
178                                    for (int i = 0; i < useArray.length; i++) {
179                                            _useSet.add(useArray[i]);
180                                    }
181                            }
182                    }
183    
184                    public void append(StringBundler contentSB, String use) {
185                            if (Validator.isNull(use)) {
186                                    _rawSB.append(contentSB);
187                            }
188                            else {
189                                    _callbackSB.append("(function() {");
190                                    _callbackSB.append(contentSB);
191                                    _callbackSB.append("})();");
192    
193                                    String[] useArray = StringUtil.split(use);
194    
195                                    for (int i = 0; i < useArray.length; i++) {
196                                            _useSet.add(useArray[i]);
197                                    }
198                            }
199                    }
200    
201                    private static final long serialVersionUID = 1L;
202    
203                    private StringBundler _callbackSB = new StringBundler();
204                    private StringBundler _rawSB = new StringBundler();
205                    private Set<String> _useSet = new TreeSet<String>();
206    
207            }
208    
209    }