Mercurial Hosting > nabble
annotate src/nabble/view/web/app/Addons.jtp @ 62:4674ed7d56df default tip
remove n2
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sat, 30 Sep 2023 20:25:29 -0600 |
parents | 72765b66e2c3 |
children |
rev | line source |
---|---|
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."); | |
35 | 71 addModule("Content", "semiprivate", "Restrict to registered users", "Only allow registered users to view the forum."); |
0 | 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("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)."); | |
76 | |
77 addModule("Responsiveness", "responsive", "Responsive layout", "Add-on that improves the responsiveness of Nabble apps and make pages more readable on small screens."); | |
78 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)."); | |
79 | |
80 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."); | |
81 | |
82 addModule("Work", "workgroup", "Workgroup", | |
83 "This feature allows a team to work integrated with a forum. " + | |
84 "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." + | |
85 "Each topic represents a task that holds the discussion about the work to be accomplished.<br/>" + | |
62 | 86 "<a href=\"https://support.nabble.com/Workgroups-tt1559166.html\">Learn more</a>" |
0 | 87 ); |
88 | |
89 addModule("Voting & Survey", "poll", "Polls", "Allows you to add polls/surveys to your posts and collect votes from your visitors. " + | |
90 "You will find options to add a new poll when you create a new topic or reply to a post." + | |
91 "By default, only administrators can create polls. If you want to let other groups create polls, just modify the Create_poll permission. "); | |
92 } | |
93 | |
94 protected void service(HttpServletRequest request,HttpServletResponse response) | |
95 throws ServletException, IOException | |
96 { | |
97 Site site = Jtp.getSite(request); | |
98 if (site == null) { | |
99 response.sendError(HttpServletResponse.SC_NOT_FOUND, "No application match the \"<i>" + request.getHeader("host") + "</i>\" domain."); | |
100 return; | |
101 } | |
102 | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
103 User user = Jtp.getUser(request); |
0 | 104 if (user == null) { |
105 response.sendRedirect(site.getBaseUrl() + Jtp.loginPath(site,null,response.encodeURL("/forum/Addons.jtp?site="+site.getId())) ); | |
106 return; | |
107 } | |
108 | |
109 boolean isSiteAdmin = Permissions.isInGroup(user, Permissions.ADMINISTRATORS_GROUP); | |
110 boolean isSysAdmin = Permissions.isSysAdmin(user); | |
111 if (!isSiteAdmin && !isSysAdmin) { | |
112 Jtp.login("Only administrators can proceed in this area.", request, response); | |
113 return; | |
114 } | |
115 | |
116 boolean isSave = "save".equals(request.getParameter("action")); | |
117 | |
118 String errorMsg = null; | |
119 if (isSave && "POST".equals(request.getMethod())) { | |
120 DbDatabase db = site.getDb(); | |
121 db.beginTransaction(); | |
122 try { | |
123 site = site.getGoodCopy(); | |
124 for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { | |
125 for (ModuleInfo info : entry.getValue()) { | |
126 boolean isEnabled = "y".equals(request.getParameter(info.moduleName)); | |
127 site.setModuleEnabled(info.moduleName, isEnabled); | |
128 } | |
129 } | |
130 | |
131 db.commitTransaction(); | |
132 Jtp.sendRedirect(request,response,Jtp.path(site.getRootNode())); | |
133 return; | |
134 } finally { | |
135 db.endTransaction(); | |
136 } | |
137 } | |
138 Node rootNode = site.getRootNode(); | |
139 PrintWriter out = response.getWriter(); | |
140 %> | |
141 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
142 <html> | |
143 <head> | |
144 <META NAME="robots" CONTENT="noindex,nofollow"> | |
145 <% Shared.title(request, response, "Extras & add-ons"); %> | |
146 <% style(out); %> | |
147 <% js(out); %> | |
148 </head> | |
149 <body> | |
150 <% Shared.minHeader(request,response, rootNode); %> | |
151 | |
152 <div style="padding:.5em 0 .5em 60px;background:url('/images/box.png') 0 5px no-repeat;min-height:40px"> | |
153 <div class="big-title second-font">Extras & Add-ons</div> | |
154 <div class="weak-color"> | |
155 Select below the extra features and add-ons for your Nabble application. | |
156 </div> | |
157 </div> | |
158 | |
159 <% Shared.errorMessage(request, response, errorMsg, null); %> | |
160 | |
161 <form method="post" action="/app/Addons.jtp" accept-charset="UTF-8"> | |
162 <input type="hidden" name="action" value="save"/> | |
163 <table class="vertical-control"> | |
164 <tr> | |
165 <td> | |
166 <ul class="vertical-control"> | |
167 <% for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { %> | |
168 <li id="tab_<%=elementId(entry.getKey())%>" <%=entry.getKey().equals(firstTab)?"class=\"selected shaded-bg-color\"":""%>><%=entry.getKey()%></li> | |
169 <% } %> | |
170 </ul> | |
171 </td> | |
172 <td class="details shaded-bg-color"> | |
173 <% for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { %> | |
174 <div id="div_<%=elementId(entry.getKey())%>" <%=entry.getKey().equals(firstTab)?"":"style=\"display:none\""%>> | |
175 <% for (ModuleInfo info : entry.getValue()) { %> | |
176 <% boolean isChecked = site.isModuleEnabled(info.moduleName); %> | |
177 <div class="addon-option"> | |
178 <input id="_<%=info.moduleName%>" type="checkbox" name="<%=info.moduleName%>" value="y" <%=isChecked?"checked=\"true\"":""%>/> | |
179 <label for="_<%=info.moduleName%>"><%=info.name%></label> | |
180 <% if (info.description != null && info.description.length() > 0) { %> | |
181 <div class="weak-color" style="margin:.25em 1.8em 1.4em"><%=info.description%></div> | |
182 <% } %> | |
183 </div> | |
184 <% } %> | |
185 </div> | |
186 <% } %> | |
187 </td> | |
188 </tr> | |
189 </table> | |
190 <input type="submit" class="toolbar action-button" value="Save Changes"/> | |
191 or <a href="<%=Jtp.path(rootNode)%>">Cancel</a> | |
192 </form> | |
193 | |
194 <% Shared.footer(request, response); %> | |
195 <% Shared.analytics(request, response); %> | |
196 </body> | |
197 </html> | |
198 <% | |
199 } | |
200 | |
201 private static String elementId(String name) { | |
202 return name.replaceAll(" ","_").replaceAll("&",""); | |
203 } | |
204 | |
205 private static void js(PrintWriter out) { | |
206 %> | |
207 <script type="text/javascript"> | |
208 var selectedTab = '<%=firstTab%>'; | |
209 $(document).ready(function() { | |
210 var $li = $('ul.vertical-control li'); | |
211 $li.click(function() { | |
212 var $this = $(this); | |
213 if ($this.hasClass('selected')) | |
214 return; | |
215 $('#tab_'+selectedTab).removeClass('selected shaded-bg-color'); | |
216 $('#div_'+selectedTab).hide(); | |
217 selectedTab = $this.attr('id').substring(4); | |
218 $('#tab_'+selectedTab).addClass('selected shaded-bg-color'); | |
219 $('#div_'+selectedTab).show(); | |
220 Nabble.resizeFrames(); | |
221 }); | |
222 $li.hover(function() { | |
223 var $this = $(this); | |
224 if ($this.hasClass('selected')) | |
225 return; | |
226 $this.addClass('light-bg-color'); | |
227 }, function() { | |
228 var $this = $(this); | |
229 $this.removeClass('light-bg-color'); | |
230 }); | |
231 }); | |
232 </script> | |
233 <% | |
234 } | |
235 | |
236 private static void style(PrintWriter out) { | |
237 %> | |
238 <style type="text/css"> | |
239 input { vertical-align:-10%; } | |
240 label { | |
241 font-weight: bold; | |
242 cursor: pointer; | |
243 } | |
244 | |
245 div.addon-option { | |
246 margin: 0 0 .5em; | |
247 } | |
248 table.vertical-control { | |
249 margin: 1em 0; | |
250 width:100%; | |
251 border-collapse:collapse; | |
252 } | |
253 table.vertical-control td { | |
254 padding:0; | |
255 vertical-align:top; | |
256 } | |
257 table.vertical-control td.details { | |
258 width:85%; | |
259 padding:1em .8em .8em; | |
260 } | |
261 ul.vertical-control { | |
262 width:100%; | |
263 list-style-type:none; | |
264 padding:0; | |
265 margin:0; | |
266 } | |
267 ul.vertical-control li { | |
268 padding: .3em 0 .3em 1em; | |
269 font-weight:bold; | |
270 white-space:nowrap; | |
271 cursor:pointer; | |
272 border-top-left-radius:5px; | |
273 border-bottom-left-radius:5px; | |
274 -moz-border-radius-topleft:5px; | |
275 -moz-border-radius-bottomleft:5px; | |
276 } | |
277 ul.vertical-control li.selected { | |
278 cursor:text; | |
279 text-shadow:1px 1px 0 white; | |
280 } | |
281 </style> | |
282 <% | |
283 } | |
284 } | |
285 %> |