/********************************************************************************** * $URL:https://source.sakaiproject.org/svn/osp/trunk/glossary/tool-lib/src/java/org/theospi/portfolio/help/control/GlossaryTag.java $ * $Id:GlossaryTag.java 9134 2006-05-08 20:28:42Z chmaurer@iupui.edu $ *********************************************************************************** * * Copyright (c) 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.theospi.portfolio.help.helper; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Collection; import java.util.HashSet; import javax.servlet.jsp.JspWriter; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.cover.SessionManager; import org.theospi.portfolio.help.model.GlossaryEntry; import org.theospi.portfolio.help.model.HelpManager; public class HelpTagHelper { static public void renderHelp(Reader reader, int charCount, Writer writer, GlossaryEntry[] terms, boolean firstOnly, boolean hover, boolean link) throws IOException { boolean wordState = true; boolean inPhrase = false; StringBuilder buf = new StringBuilder(); Collection foundWords = new HashSet(); for (int i = 0; i < charCount; i++) { char in = (char) reader.read(); if (wordState && isWordBoundary(in)) { // check if the captured phrase is a part of any of the terms boolean currentPhrase = isPhraseStart(buf.toString() + in, terms); if (currentPhrase) { inPhrase = true; buf.append(in); continue; } GlossaryEntry entry = searchGlossary(buf.toString(), terms); if (inPhrase && entry == null) { outputPhrase(writer, buf, foundWords, terms, firstOnly, hover, link); inPhrase = false; } else if (entry == null || (firstOnly && foundWords.contains(buf.toString()))) { writer.write(buf.toString()); } else { writer.write(getMarkup(buf.toString(), entry, hover, link)); foundWords.add(buf.toString()); } // If we are going into an HTML tog then stop if (in == '<') { wordState = false; } writer.write(in); buf = new StringBuilder(); } else if (wordState) { buf.append(in); } else if (in == '>') { // If we are going out of an HTML tog then start wordState = true; writer.write(in); } else { writer.write(in); } } if (buf != null) { handleLast(writer, buf, terms, inPhrase, foundWords, firstOnly, hover, link); } } static protected void handleLast(Writer out, StringBuilder buf, GlossaryEntry[] terms, boolean inPhrase, Collection foundWords, boolean firstOnly, boolean hover, boolean link) throws IOException { GlossaryEntry entry = searchGlossary(buf.toString(), terms); if (inPhrase && entry == null) { outputPhrase(out, buf, foundWords, terms, firstOnly, hover, link); inPhrase = false; } else if (entry == null || (firstOnly && foundWords.contains(buf.toString()))) { out.write(buf.toString()); } else { out.write(getMarkup(buf.toString(), entry, hover, link)); foundWords.add(buf.toString()); } } static public HelpManager getHelpManager() { return (HelpManager) ComponentManager.getInstance().get("helpManager"); } /** * Checks to see if the phrase matches the beginning of any terms * @param phrase * @param terms * @return boolean */ static protected boolean isPhraseStart(String phrase, GlossaryEntry[] terms) { if (phrase.length() == 0) { return false; } // go backwards... more efficient //each term must be translated into it's html equivalent // the phrase may not have the whole html equivalent yet. for (int i=terms.length - 1;i>=0;i--) { GlossaryEntry entry = terms[i]; String term = entry.getTerm(); term = term.replaceAll("&", "&"); term = term.replaceAll(">", ">"); term = term.replaceAll("<", "<"); if (term.toLowerCase().startsWith(phrase.toLowerCase())) { return true; } } return false; } static protected GlossaryEntry searchGlossary(String phrase, GlossaryEntry[] terms) { phrase = phrase.replaceAll("&", "&"); phrase = phrase.replaceAll(">", ">"); phrase = phrase.replaceAll("<", "<"); for (int i=0;i<terms.length;i++) { GlossaryEntry entry = terms[i]; if (entry.getTerm().toLowerCase().equals(phrase.toLowerCase())) { return entry; } } return null; } static protected void outputPhrase(Writer out, StringBuilder buf, Collection foundWords, GlossaryEntry[] terms, boolean firstOnly, boolean hover, boolean link) throws IOException { StringBuilder newBuf = new StringBuilder(); boolean firstWord = false; boolean inPhrase = false; for (int i=0;i<buf.length();i++) { char in = buf.charAt(i); if (isWordBoundary(in) && newBuf.length() > 0) { boolean currentPhrase = false; GlossaryEntry entry = null; if (firstWord) { currentPhrase = isPhraseStart(newBuf.toString() + in, terms); } firstWord = true; if (!currentPhrase) { entry = searchGlossary(newBuf.toString(), terms); } else { inPhrase = true; newBuf.append(in); continue; } if (inPhrase && entry == null) { outputPhrase(out, newBuf, foundWords, terms, firstOnly, hover, link); inPhrase = false; } else if (entry == null || (firstOnly && foundWords.contains(newBuf.toString()))) { out.write(newBuf.toString()); out.write(in); } else { out.write(getMarkup(newBuf.toString(), entry, hover, link)); foundWords.add(newBuf.toString()); out.write(in); } newBuf = new StringBuilder(); } else if (isWordBoundary(in)) { out.write(in); } else { newBuf.append(in); } } GlossaryEntry entry = searchGlossary(newBuf.toString(), terms); if (entry == null || (firstOnly && foundWords.contains(newBuf.toString()))) { out.write(newBuf.toString()); } else { out.write(getMarkup(newBuf.toString(), entry, hover, link)); foundWords.add(newBuf.toString()); } } static protected String getMarkup(String originalTerm, GlossaryEntry entry, boolean hover, boolean link) { StringBuilder markup = new StringBuilder(); String url = ServerConfigurationService.getServerUrl(); String linkName = url + getHelpManager().getGlossary().getUrl() + "?id=" + entry.getId(); linkName += "&" + Tool.PLACEMENT_ID + "=" + SessionManager.getCurrentToolSession().getPlacementId(); markup.append("<a href=\"#\" onclick=\"openNewWindow('" + linkName + "');return false;\""); if (hover) { markup.append(" onMouseover=\"showtip(this,event,'" + replaceQuotes(entry.getDescription()) + "')\" onMouseOut=\"hidetip()\" "); } if (!link) { markup.append(" onClick=\"return false\" "); } markup.append(">" + originalTerm); markup.append("</a>"); return markup.toString(); } static protected String replaceQuotes(String description) { // replace \ with \\ description = description.replaceAll("\\\\", "\\\\\\\\"); // replace ' with \' description = description.replaceAll("\\\'", "\\\\'"); // replace " with " description = description.replaceAll("\\\"", """); return description; } static protected boolean isWordBoundary(char c) { // matching [\s] means white space and \p{Punct} is for any punctuation return String.valueOf(c).matches("[\\s\\p{Punct}]"); } }