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.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.List;
031    import java.util.Set;
032    import java.util.TreeSet;
033    import java.util.concurrent.ConcurrentHashMap;
034    import java.util.concurrent.ConcurrentMap;
035    
036    import javax.servlet.http.HttpServletRequest;
037    
038    /**
039     * @author Brian Wing Shun Chan
040     * @author Shuyang Zhou
041     */
042    public class ScriptData implements Mergeable<ScriptData>, Serializable {
043    
044            public void append(String portletId, String content, String use) {
045                    PortletData portletData = _getPortletData(portletId);
046    
047                    portletData.append(content, use);
048            }
049    
050            public void append(String portletId, StringBundler contentSB, String use) {
051                    PortletData portletData = _getPortletData(portletId);
052    
053                    portletData.append(contentSB, use);
054            }
055    
056            public void mark() {
057                    for (PortletData portletData : _portletDataMap.values()) {
058                            _addToSBIndexList(portletData._callbackSB);
059                            _addToSBIndexList(portletData._rawSB);
060                    }
061            }
062    
063            @Override
064            public ScriptData merge(ScriptData scriptData) {
065                    if ((scriptData != null) && (scriptData != this)) {
066                            _portletDataMap.putAll(scriptData._portletDataMap);
067                    }
068    
069                    return this;
070            }
071    
072            public void reset() {
073                    for (ObjectValuePair<StringBundler, Integer> ovp : _sbIndexList) {
074                            StringBundler sb = ovp.getKey();
075    
076                            sb.setIndex(ovp.getValue());
077                    }
078            }
079    
080            public void writeTo(HttpServletRequest request, Writer writer)
081                    throws IOException {
082    
083                    writer.write("<script type=\"text/javascript\">\n// <![CDATA[\n");
084    
085                    StringBundler callbackSB = new StringBundler();
086    
087                    for (PortletData portletData : _portletDataMap.values()) {
088                            portletData._rawSB.writeTo(writer);
089    
090                            callbackSB.append(portletData._callbackSB);
091                    }
092    
093                    if (callbackSB.index() == 0) {
094                            writer.write("\n// ]]>\n</script>");
095    
096                            return;
097                    }
098    
099                    String loadMethod = "use";
100    
101                    if (BrowserSnifferUtil.isIe(request) &&
102                            (BrowserSnifferUtil.getMajorVersion(request) < 8)) {
103    
104                            loadMethod = "ready";
105                    }
106    
107                    writer.write("AUI().");
108                    writer.write(loadMethod);
109                    writer.write("(");
110    
111                    Set<String> useSet = new TreeSet<String>();
112    
113                    for (PortletData portletData : _portletDataMap.values()) {
114                            useSet.addAll(portletData._useSet);
115                    }
116    
117                    for (String use : useSet) {
118                            writer.write(StringPool.APOSTROPHE);
119                            writer.write(use);
120                            writer.write(StringPool.APOSTROPHE);
121                            writer.write(StringPool.COMMA_AND_SPACE);
122                    }
123    
124                    writer.write("function(A) {");
125    
126                    callbackSB.writeTo(writer);
127    
128                    writer.write("});");
129    
130                    writer.write("\n// ]]>\n</script>");
131            }
132    
133            private void _addToSBIndexList(StringBundler sb) {
134                    ObjectValuePair<StringBundler, Integer> ovp =
135                            new ObjectValuePair<StringBundler, Integer>(sb, sb.index());
136    
137                    int index = _sbIndexList.indexOf(ovp);
138    
139                    if (index == -1) {
140                            _sbIndexList.add(ovp);
141                    }
142                    else {
143                            ovp = _sbIndexList.get(index);
144    
145                            ovp.setValue(sb.index());
146                    }
147            }
148    
149            private PortletData _getPortletData(String portletId) {
150                    if (Validator.isNull(portletId)) {
151                            portletId = StringPool.BLANK;
152                    }
153    
154                    PortletData portletData = _portletDataMap.get(portletId);
155    
156                    if (portletData == null) {
157                            portletData = new PortletData();
158    
159                            PortletData oldPortletData = _portletDataMap.putIfAbsent(
160                                    portletId, portletData);
161    
162                            if (oldPortletData != null) {
163                                    portletData = oldPortletData;
164                            }
165                    }
166    
167                    return portletData;
168            }
169    
170            private static final long serialVersionUID = 1L;
171    
172            private ConcurrentMap<String, PortletData> _portletDataMap =
173                    new ConcurrentHashMap<String, PortletData>();
174            private List<ObjectValuePair<StringBundler, Integer>> _sbIndexList =
175                    new ArrayList<ObjectValuePair<StringBundler, Integer>>();
176    
177            private class PortletData implements Serializable {
178    
179                    public void append(String content, String use) {
180                            if (Validator.isNull(use)) {
181                                    _rawSB.append(content);
182                            }
183                            else {
184                                    _callbackSB.append("(function() {");
185                                    _callbackSB.append(content);
186                                    _callbackSB.append("})();");
187    
188                                    String[] useArray = StringUtil.split(use);
189    
190                                    for (int i = 0; i < useArray.length; i++) {
191                                            _useSet.add(useArray[i]);
192                                    }
193                            }
194                    }
195    
196                    public void append(StringBundler contentSB, String use) {
197                            if (Validator.isNull(use)) {
198                                    _rawSB.append(contentSB);
199                            }
200                            else {
201                                    _callbackSB.append("(function() {");
202                                    _callbackSB.append(contentSB);
203                                    _callbackSB.append("})();");
204    
205                                    String[] useArray = StringUtil.split(use);
206    
207                                    for (int i = 0; i < useArray.length; i++) {
208                                            _useSet.add(useArray[i]);
209                                    }
210                            }
211                    }
212    
213                    private static final long serialVersionUID = 1L;
214    
215                    private StringBundler _callbackSB = new StringBundler();
216                    private StringBundler _rawSB = new StringBundler();
217                    private Set<String> _useSet = new TreeSet<String>();
218    
219            }
220    
221    }