0
|
1 <%
|
|
2 package nabble.view.web.app;
|
|
3
|
|
4 import fschmidt.db.DbDatabase;
|
|
5 import nabble.model.Node;
|
|
6 import nabble.model.Site;
|
|
7 import nabble.model.User;
|
|
8 import nabble.view.lib.Jtp;
|
|
9 import nabble.view.lib.Permissions;
|
|
10 import nabble.view.lib.Shared;
|
|
11
|
|
12 import javax.servlet.ServletException;
|
|
13 import javax.servlet.http.HttpServlet;
|
|
14 import javax.servlet.http.HttpServletRequest;
|
|
15 import javax.servlet.http.HttpServletResponse;
|
|
16 import java.io.IOException;
|
|
17 import java.io.PrintWriter;
|
|
18 import java.util.ArrayList;
|
|
19 import java.util.LinkedHashMap;
|
|
20 import java.util.List;
|
|
21 import java.util.Map;
|
|
22
|
|
23
|
|
24 public final class Addons extends HttpServlet {
|
|
25
|
|
26 private static class ModuleInfo {
|
|
27 String moduleName;
|
|
28 String name;
|
|
29 String description;
|
|
30 }
|
|
31
|
|
32 private static Map<String, List<ModuleInfo>> modulesByCategory = new LinkedHashMap<String, List<ModuleInfo>>();
|
|
33
|
|
34 private static String firstTab;
|
|
35
|
|
36 private static void addModule(String category, String moduleName, String name, String description) {
|
|
37 if (firstTab == null)
|
|
38 firstTab = category;
|
|
39 List<ModuleInfo> list = modulesByCategory.get(category);
|
|
40 if (list == null) {
|
|
41 list = new ArrayList<ModuleInfo>();
|
|
42 modulesByCategory.put(category, list);
|
|
43 }
|
|
44 ModuleInfo info = new ModuleInfo();
|
|
45 info.moduleName = moduleName;
|
|
46 info.name = name;
|
|
47 info.description = description;
|
|
48 list.add(info);
|
|
49 }
|
|
50
|
|
51 static {
|
|
52 addModule("Social", "social_dropdown_links", "Social dropdown links", "Show social links under the \"More\" menu of posts. With these links, users will be able to easily post to Twitter, Facebook, Delicious, Stumble Upon, LinkedIn, Google Bookmarks and Digg, which helps promoting your site.");
|
|
53 addModule("Social", "social_google_plus_one", "Google +1 button", "Show the Google +1 button on the top of the topic page.<br/><a href=\"http://www.google.com/+1/button/\" rel=\"nofollow\">Learn more</a>");
|
|
54 addModule("Social", "social_facebook_like", "Facebook like button", "Show the Facebook Like button on the top of the topic page. <br/><a href=\"http://developers.facebook.com/docs/reference/plugins/like/\" rel=\"nofollow\">Learn more</a>");
|
|
55 addModule("Social", "social_tweet", "Tweet button", "Show Twitter / Tweet button on the top of the topic page. <br/><a href=\"http://twitter.com/about/resources/tweetbutton\" rel=\"nofollow\">Learn more</a>");
|
|
56
|
|
57 addModule("Content", "content_noindex", "Hide contents from search engines", "Select this checkbox if you want to prevent Google and other search engines from indexing the contents of this application.");
|
|
58 addModule("Content", "content_open_links_in_new_window", "Open links in new window", "Links posted by users will open in a different tab or window.");
|
|
59 addModule("Content", "content_smart_cache", "Smart application pages",
|
|
60 "If your application has private sub-forums (or any other private sub-app), you can use this feature to make app pages always display the contents that the user can view. "+
|
|
61 "In other words, if a user has access to a private sub-forum, he/she will be able to view the private contents from the top-level app. "+
|
|
62 "Other users (without access) will only view the public contents. "+
|
|
63 "<b>Note</b>: this feature may slow down your app pages a little bit because the system must generate them from scratch for each user. You will probably not notice any difference if your application is small (e.g., less than 5,000 topics).");
|
|
64 addModule("Content", "content_news_summary", "Custom summary for Newspaper",
|
|
65 "If you use the Newspaper application type, you can use this add-on to define custom snippets for your posts "+
|
|
66 "(the snippet is the text that shows on the front page of the app, immediately below the title of the post). " +
|
|
67 "You can specify the snippet directly in the post message like this: \"{summary_start} Here is your summary text {summary_end} Here is the post message.\" "+
|
|
68 "The text between the tags is the snippet to be displayed on the news page and will NOT appear on the post page."
|
|
69 );
|
|
70 addModule("Content", "forum_avatars", "Show avatars on forum page", "Shows the avatar for the first and last post of each topic on the forum page.");
|
|
71 addModule("Content", "ads", "Show ads", "Support Nabble by allowing us to show ads.");
|
|
72
|
|
73 addModule("Email & Notifications", "email_registration_notification", "Notify me when someone registers", "When a user completes the registration process, an email is sent to all administrators with the details of the user (e.g., username, email, link to profile page).");
|
|
74
|
|
75 addModule("Mailing List Archives", "expire_old_threads", "Lock old threads", "This add-on prevents new replies to old threads, which could be confusing to the mailing list users. Users that try to reply to an old thread will see a message that suggests them to create a new topic instead. By default, a thread is locked if it was created more than 365 days ago. You can change this number by tweaking the \"thread_expiration_days\" macro. ");
|
|
76
|
|
77 addModule("Privacy & Law", "cookie_policy", "Cookie Law Compliance Solution", "Add-on for obtaining a user's explicit consent for the use of cookies on their browsers. This is required by some countries (mainly UK and EU) and visitors must explicitly agree with the E-Privacy Directive before having cookies read from/written to their browsers. The consent is requested just once. By default, the consent is requested to UK visitors only, but you can change the list of countries with NAML (i.e., override the <i>cookie_countries</i> macro).");
|
|
78
|
|
79 addModule("Responsiveness", "responsive", "Responsive layout", "Add-on that improves the responsiveness of Nabble apps and make pages more readable on small screens.");
|
|
80 addModule("Responsiveness", "mobile", "Better new post interface for mobile users", "Add-on that provides a better \"new topic\" and \"reply\" interfaces for mobile users. Posting new messages from cell phones (or any device with a small screen) will be easier with this module. Only mobile users will see the optimized pages (other users will still see the default new topic and reply pages).");
|
|
81
|
|
82 addModule("Navigation", "thread_navigation", "Show links to next/previous threads", "This add-on adds \"Previous Thread\" and \"Next Thread\" links to the top of each thread page. Navigation through the threads becomes easier since users don't have to return to the front page in order to visit other threads.");
|
|
83
|
|
84 addModule("Work", "workgroup", "Workgroup",
|
|
85 "This feature allows a team to work integrated with a forum. " +
|
|
86 "Basically, a user can assign a topic to another user with a priority that ranges from 1 (highest) to 5 (lowest).This feature allows a team to work integrated with a forum." +
|
|
87 "Each topic represents a task that holds the discussion about the work to be accomplished.<br/>" +
|
|
88 "<a href=\"http://nabble-support.1.n2.nabble.com/Workgroups-td1559166.html\">Learn more</a>"
|
|
89 );
|
|
90
|
|
91 addModule("Voting & Survey", "poll", "Polls", "Allows you to add polls/surveys to your posts and collect votes from your visitors. " +
|
|
92 "You will find options to add a new poll when you create a new topic or reply to a post." +
|
|
93 "By default, only administrators can create polls. If you want to let other groups create polls, just modify the Create_poll permission. ");
|
|
94 }
|
|
95
|
|
96 protected void service(HttpServletRequest request,HttpServletResponse response)
|
|
97 throws ServletException, IOException
|
|
98 {
|
|
99 Site site = Jtp.getSite(request);
|
|
100 if (site == null) {
|
|
101 response.sendError(HttpServletResponse.SC_NOT_FOUND, "No application match the \"<i>" + request.getHeader("host") + "</i>\" domain.");
|
|
102 return;
|
|
103 }
|
|
104
|
|
105 User user = Jtp.getUser(request, response);
|
|
106 if (user == null) {
|
|
107 response.sendRedirect(site.getBaseUrl() + Jtp.loginPath(site,null,response.encodeURL("/forum/Addons.jtp?site="+site.getId())) );
|
|
108 return;
|
|
109 }
|
|
110
|
|
111 boolean isSiteAdmin = Permissions.isInGroup(user, Permissions.ADMINISTRATORS_GROUP);
|
|
112 boolean isSysAdmin = Permissions.isSysAdmin(user);
|
|
113 if (!isSiteAdmin && !isSysAdmin) {
|
|
114 Jtp.login("Only administrators can proceed in this area.", request, response);
|
|
115 return;
|
|
116 }
|
|
117
|
|
118 boolean isSave = "save".equals(request.getParameter("action"));
|
|
119
|
|
120 String errorMsg = null;
|
|
121 if (isSave && "POST".equals(request.getMethod())) {
|
|
122 DbDatabase db = site.getDb();
|
|
123 db.beginTransaction();
|
|
124 try {
|
|
125 site = site.getGoodCopy();
|
|
126 for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) {
|
|
127 for (ModuleInfo info : entry.getValue()) {
|
|
128 boolean isEnabled = "y".equals(request.getParameter(info.moduleName));
|
|
129 site.setModuleEnabled(info.moduleName, isEnabled);
|
|
130 }
|
|
131 }
|
|
132
|
|
133 db.commitTransaction();
|
|
134 Jtp.sendRedirect(request,response,Jtp.path(site.getRootNode()));
|
|
135 return;
|
|
136 } finally {
|
|
137 db.endTransaction();
|
|
138 }
|
|
139 }
|
|
140 Node rootNode = site.getRootNode();
|
|
141 PrintWriter out = response.getWriter();
|
|
142 %>
|
|
143 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
144 <html>
|
|
145 <head>
|
|
146 <META NAME="robots" CONTENT="noindex,nofollow">
|
|
147 <% Shared.title(request, response, "Extras & add-ons"); %>
|
|
148 <% style(out); %>
|
|
149 <% js(out); %>
|
|
150 </head>
|
|
151 <body>
|
|
152 <% Shared.minHeader(request,response, rootNode); %>
|
|
153
|
|
154 <div style="padding:.5em 0 .5em 60px;background:url('/images/box.png') 0 5px no-repeat;min-height:40px">
|
|
155 <div class="big-title second-font">Extras & Add-ons</div>
|
|
156 <div class="weak-color">
|
|
157 Select below the extra features and add-ons for your Nabble application.
|
|
158 </div>
|
|
159 </div>
|
|
160
|
|
161 <% Shared.errorMessage(request, response, errorMsg, null); %>
|
|
162
|
|
163 <form method="post" action="/app/Addons.jtp" accept-charset="UTF-8">
|
|
164 <input type="hidden" name="action" value="save"/>
|
|
165 <table class="vertical-control">
|
|
166 <tr>
|
|
167 <td>
|
|
168 <ul class="vertical-control">
|
|
169 <% for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { %>
|
|
170 <li id="tab_<%=elementId(entry.getKey())%>" <%=entry.getKey().equals(firstTab)?"class=\"selected shaded-bg-color\"":""%>><%=entry.getKey()%></li>
|
|
171 <% } %>
|
|
172 </ul>
|
|
173 </td>
|
|
174 <td class="details shaded-bg-color">
|
|
175 <% for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { %>
|
|
176 <div id="div_<%=elementId(entry.getKey())%>" <%=entry.getKey().equals(firstTab)?"":"style=\"display:none\""%>>
|
|
177 <% for (ModuleInfo info : entry.getValue()) { %>
|
|
178 <% boolean isChecked = site.isModuleEnabled(info.moduleName); %>
|
|
179 <div class="addon-option">
|
|
180 <input id="_<%=info.moduleName%>" type="checkbox" name="<%=info.moduleName%>" value="y" <%=isChecked?"checked=\"true\"":""%>/>
|
|
181 <label for="_<%=info.moduleName%>"><%=info.name%></label>
|
|
182 <% if (info.description != null && info.description.length() > 0) { %>
|
|
183 <div class="weak-color" style="margin:.25em 1.8em 1.4em"><%=info.description%></div>
|
|
184 <% } %>
|
|
185 </div>
|
|
186 <% } %>
|
|
187 </div>
|
|
188 <% } %>
|
|
189 </td>
|
|
190 </tr>
|
|
191 </table>
|
|
192 <input type="submit" class="toolbar action-button" value="Save Changes"/>
|
|
193 or <a href="<%=Jtp.path(rootNode)%>">Cancel</a>
|
|
194 </form>
|
|
195
|
|
196 <% Shared.footer(request, response); %>
|
|
197 <% Shared.analytics(request, response); %>
|
|
198 </body>
|
|
199 </html>
|
|
200 <%
|
|
201 }
|
|
202
|
|
203 private static String elementId(String name) {
|
|
204 return name.replaceAll(" ","_").replaceAll("&","");
|
|
205 }
|
|
206
|
|
207 private static void js(PrintWriter out) {
|
|
208 %>
|
|
209 <script type="text/javascript">
|
|
210 var selectedTab = '<%=firstTab%>';
|
|
211 $(document).ready(function() {
|
|
212 var $li = $('ul.vertical-control li');
|
|
213 $li.click(function() {
|
|
214 var $this = $(this);
|
|
215 if ($this.hasClass('selected'))
|
|
216 return;
|
|
217 $('#tab_'+selectedTab).removeClass('selected shaded-bg-color');
|
|
218 $('#div_'+selectedTab).hide();
|
|
219 selectedTab = $this.attr('id').substring(4);
|
|
220 $('#tab_'+selectedTab).addClass('selected shaded-bg-color');
|
|
221 $('#div_'+selectedTab).show();
|
|
222 Nabble.resizeFrames();
|
|
223 });
|
|
224 $li.hover(function() {
|
|
225 var $this = $(this);
|
|
226 if ($this.hasClass('selected'))
|
|
227 return;
|
|
228 $this.addClass('light-bg-color');
|
|
229 }, function() {
|
|
230 var $this = $(this);
|
|
231 $this.removeClass('light-bg-color');
|
|
232 });
|
|
233 });
|
|
234 </script>
|
|
235 <%
|
|
236 }
|
|
237
|
|
238 private static void style(PrintWriter out) {
|
|
239 %>
|
|
240 <style type="text/css">
|
|
241 input { vertical-align:-10%; }
|
|
242 label {
|
|
243 font-weight: bold;
|
|
244 cursor: pointer;
|
|
245 }
|
|
246
|
|
247 div.addon-option {
|
|
248 margin: 0 0 .5em;
|
|
249 }
|
|
250 table.vertical-control {
|
|
251 margin: 1em 0;
|
|
252 width:100%;
|
|
253 border-collapse:collapse;
|
|
254 }
|
|
255 table.vertical-control td {
|
|
256 padding:0;
|
|
257 vertical-align:top;
|
|
258 }
|
|
259 table.vertical-control td.details {
|
|
260 width:85%;
|
|
261 padding:1em .8em .8em;
|
|
262 }
|
|
263 ul.vertical-control {
|
|
264 width:100%;
|
|
265 list-style-type:none;
|
|
266 padding:0;
|
|
267 margin:0;
|
|
268 }
|
|
269 ul.vertical-control li {
|
|
270 padding: .3em 0 .3em 1em;
|
|
271 font-weight:bold;
|
|
272 white-space:nowrap;
|
|
273 cursor:pointer;
|
|
274 border-top-left-radius:5px;
|
|
275 border-bottom-left-radius:5px;
|
|
276 -moz-border-radius-topleft:5px;
|
|
277 -moz-border-radius-bottomleft:5px;
|
|
278 }
|
|
279 ul.vertical-control li.selected {
|
|
280 cursor:text;
|
|
281 text-shadow:1px 1px 0 white;
|
|
282 }
|
|
283 </style>
|
|
284 <%
|
|
285 }
|
|
286 }
|
|
287 %>
|