001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2004 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.plugin;
021:
022: import org.apache.log4j.Logger;
023: import com.ecyrd.jspwiki.*;
024: import com.ecyrd.jspwiki.parser.Heading;
025: import com.ecyrd.jspwiki.parser.HeadingListener;
026: import com.ecyrd.jspwiki.parser.JSPWikiMarkupParser;
027:
028: import java.util.*;
029: import java.io.StringReader;
030: import java.io.IOException;
031:
032: /**
033: * Provides a table of contents.
034: *
035: * @since 2.2
036: * @author Janne Jalkanen
037: */
038: public class TableOfContents implements WikiPlugin, HeadingListener {
039: private static Logger log = Logger.getLogger(TableOfContents.class);
040:
041: public static final String PARAM_TITLE = "title";
042: public static final String PARAM_NUMBERED = "numbered";
043: public static final String PARAM_START = "start";
044: public static final String PARAM_PREFIX = "prefix";
045:
046: private static final String VAR_ALREADY_PROCESSING = "__TableOfContents.processing";
047:
048: StringBuffer m_buf = new StringBuffer();
049: private boolean m_usingNumberedList = false;
050: private String m_prefix = "";
051: private int m_starting = 0;
052: private int m_level1Index = 0;
053: private int m_level2Index = 0;
054: private int m_level3Index = 0;
055: private int m_lastLevel = 0;
056:
057: public void headingAdded(WikiContext context, Heading hd) {
058: log.debug("HD: " + hd.m_level + ", " + hd.m_titleText + ", "
059: + hd.m_titleAnchor);
060:
061: switch (hd.m_level) {
062: case Heading.HEADING_SMALL:
063: m_buf.append("<li class=\"toclevel-3\">");
064: m_level3Index++;
065: break;
066: case Heading.HEADING_MEDIUM:
067: m_buf.append("<li class=\"toclevel-2\">");
068: m_level2Index++;
069: break;
070: case Heading.HEADING_LARGE:
071: m_buf.append("<li class=\"toclevel-1\">");
072: m_level1Index++;
073: break;
074: default:
075: throw new InternalWikiException(
076: "Unknown depth in toc! (Please submit a bug report.)");
077: }
078:
079: if (m_level1Index < m_starting) {
080: // in case we never had a large heading ...
081: m_level1Index++;
082: }
083: if ((m_lastLevel == Heading.HEADING_SMALL)
084: && (hd.m_level != Heading.HEADING_SMALL)) {
085: m_level3Index = 0;
086: }
087: if (((m_lastLevel == Heading.HEADING_SMALL) || (m_lastLevel == Heading.HEADING_MEDIUM))
088: && (hd.m_level == Heading.HEADING_LARGE)) {
089: m_level3Index = 0;
090: m_level2Index = 0;
091: }
092:
093: String titleSection = hd.m_titleSection.replace('%', '_');
094: String pageName = context.getEngine().encodeName(
095: context.getPage().getName()).replace('%', '_');
096:
097: String url = context.getURL(WikiContext.VIEW, context.getPage()
098: .getName());
099: String sectref = "#section-" + pageName + "-" + titleSection;
100:
101: m_buf.append("<a class=\"wikipage\" href=\"" + url + sectref
102: + "\">");
103: if (m_usingNumberedList) {
104: switch (hd.m_level) {
105: case Heading.HEADING_SMALL:
106: m_buf.append(m_prefix + m_level1Index + "."
107: + m_level2Index + "." + m_level3Index + " ");
108: break;
109: case Heading.HEADING_MEDIUM:
110: m_buf.append(m_prefix + m_level1Index + "."
111: + m_level2Index + " ");
112: break;
113: case Heading.HEADING_LARGE:
114: m_buf.append(m_prefix + m_level1Index + " ");
115: break;
116: default:
117: throw new InternalWikiException(
118: "Unknown depth in toc! (Please submit a bug report.)");
119: }
120: }
121: m_buf.append(TextUtil.replaceEntities(hd.m_titleText)
122: + "</a></li>\n");
123:
124: m_lastLevel = hd.m_level;
125: }
126:
127: public String execute(WikiContext context, Map params)
128: throws PluginException {
129: WikiEngine engine = context.getEngine();
130: WikiPage page = context.getPage();
131: ResourceBundle rb = context
132: .getBundle(WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE);
133:
134: if (context.getVariable(VAR_ALREADY_PROCESSING) != null)
135: return rb.getString("tableofcontents.title");
136:
137: StringBuffer sb = new StringBuffer();
138:
139: sb.append("<div class=\"toc\">\n");
140: sb.append("<div class=\"collapsebox\">\n");
141:
142: String title = (String) params.get(PARAM_TITLE);
143: if (title != null) {
144: sb.append("<h4>" + TextUtil.replaceEntities(title)
145: + "</h4>\n");
146: } else {
147: sb.append("<h4>" + rb.getString("tableofcontents.title")
148: + "</h4>\n");
149: }
150:
151: // should we use an ordered list?
152: m_usingNumberedList = false;
153: if (params.containsKey(PARAM_NUMBERED)) {
154: String numbered = (String) params.get(PARAM_NUMBERED);
155: if (numbered.equalsIgnoreCase("true")) {
156: m_usingNumberedList = true;
157: } else if (numbered.equalsIgnoreCase("yes")) {
158: m_usingNumberedList = true;
159: }
160: }
161:
162: // if we are using a numbered list, get the rest of the parameters (if any) ...
163: if (m_usingNumberedList) {
164: int start = 0;
165: String startStr = (String) params.get(PARAM_START);
166: if ((startStr != null) && (startStr.matches("^\\d+$"))) {
167: start = Integer.parseInt(startStr);
168: }
169: if (start < 0)
170: start = 0;
171:
172: m_starting = start;
173: m_level1Index = start - 1;
174: if (m_level1Index < 0)
175: m_level1Index = 0;
176: m_level2Index = 0;
177: m_level3Index = 0;
178: m_prefix = (String) params.get(PARAM_PREFIX);
179: if (m_prefix == null)
180: m_prefix = "";
181: m_lastLevel = Heading.HEADING_LARGE;
182: }
183:
184: try {
185: String wikiText = engine.getPureText(page);
186: boolean runFilters = "true".equals(engine
187: .getVariableManager().getValue(context,
188: WikiEngine.PROP_RUNFILTERS, "true"));
189:
190: try {
191: if (runFilters)
192: wikiText = engine.getFilterManager()
193: .doPreTranslateFiltering(context, wikiText);
194: } catch (Exception e) {
195: log
196: .error(
197: "Could not construct table of contents: Filter Error",
198: e);
199: throw new PluginException(
200: "Unable to construct table of contents (see logs)");
201: }
202:
203: context.setVariable(VAR_ALREADY_PROCESSING, "x");
204: JSPWikiMarkupParser parser = new JSPWikiMarkupParser(
205: context, new StringReader(wikiText));
206: parser.addHeadingListener(this );
207:
208: parser.parse();
209:
210: sb.append("<ul>\n" + m_buf.toString() + "</ul>\n");
211: } catch (IOException e) {
212: log.error("Could not construct table of contents", e);
213: throw new PluginException(
214: "Unable to construct table of contents (see logs)");
215: }
216:
217: sb.append("</div>\n</div>\n");
218:
219: return sb.toString();
220: }
221:
222: }
|