📄 jspwikimarkupparser.java
字号:
buf = buf.substring(result.endOffset(0)); m_currentElement.addContent( firstPart ); // // Check if the user does not wish to do URL or WikiWord expansion // if( prefix.endsWith("~") || prefix.indexOf('[') != -1 ) { if( prefix.endsWith("~") ) { if( m_wysiwygEditorMode ) { m_currentElement.addContent( "~" ); } prefix = prefix.substring(0,prefix.length()-1); } if( camelCase != null ) { m_currentElement.addContent( prefix+camelCase ); } else if( protocol != null ) { m_currentElement.addContent( prefix+uri ); } continue; } // // Fine, then let's check what kind of a link this was // and emit the proper elements // if( protocol != null ) { char c = uri.charAt(uri.length()-1); if( c == '.' || c == ',' ) { uri = uri.substring(0,uri.length()-1); buf = c + buf; } // System.out.println("URI match "+uri); m_currentElement.addContent( prefix ); makeDirectURILink( uri ); } else { // System.out.println("Matched: '"+camelCase+"'"); // System.out.println("Split to '"+firstPart+"', and '"+buf+"'"); // System.out.println("prefix="+prefix); m_currentElement.addContent( prefix ); makeCamelCaseLink( camelCase ); } } m_currentElement.addContent( buf ); } else { // // No camelcase asked for, just add the elements // m_currentElement.addContent( buf ); } } catch( IllegalDataException e ) { // // Sometimes it's possible that illegal XML chars is added to the data. // Here we make sure it does not stop parsing. // m_currentElement.addContent( makeError(cleanupSuspectData( e.getMessage() )) ); } } return numChars; } /** * Escapes XML entities in a HTML-compatible way (i.e. does not escape * entities that are already escaped). * * @param buf * @return An escaped string. */ private String escapeHTMLEntities(String buf) { StringBuilder tmpBuf = new StringBuilder( buf.length() + 20 ); for( int i = 0; i < buf.length(); i++ ) { char ch = buf.charAt(i); if( ch == '<' ) { tmpBuf.append("<"); } else if( ch == '>' ) { tmpBuf.append(">"); } else if( ch == '\"' ) { tmpBuf.append("""); } else if( ch == '&' ) { // // If the following is an XML entity reference (&#.*;) we'll // leave it as it is; otherwise we'll replace it with an & // boolean isEntity = false; StringBuilder entityBuf = new StringBuilder(); if( i < buf.length() -1 ) { for( int j = i; j < buf.length(); j++ ) { char ch2 = buf.charAt(j); if( Character.isLetterOrDigit( ch2 ) || (ch2 == '#' && j == i+1) || ch2 == ';' || ch2 == '&' ) { entityBuf.append(ch2); if( ch2 == ';' ) { isEntity = true; break; } } else { break; } } } if( isEntity ) { tmpBuf.append( entityBuf ); i = i + entityBuf.length() - 1; } else { tmpBuf.append("&"); } } else { tmpBuf.append( ch ); } } return tmpBuf.toString(); } private Element pushElement( Element e ) { flushPlainText(); m_currentElement.addContent( e ); m_currentElement = e; return e; } private Element addElement( Content e ) { if( e != null ) { flushPlainText(); m_currentElement.addContent( e ); } return m_currentElement; } /** * All elements that can be empty by the HTML DTD. */ // Keep sorted. private static final String[] EMPTY_ELEMENTS = { "area", "base", "br", "col", "hr", "img", "input", "link", "meta", "p", "param" }; /** * Goes through the current element stack and pops all elements until this * element is found - this essentially "closes" and element. * * @param s * @return The new current element, or null, if there was no such element in the entire stack. */ private Element popElement( String s ) { int flushedBytes = flushPlainText(); Element currEl = m_currentElement; while( currEl.getParentElement() != null ) { if( currEl.getName().equals(s) && !currEl.isRootElement() ) { m_currentElement = currEl.getParentElement(); // // Check if it's okay for this element to be empty. Then we will // trick the JDOM generator into not generating an empty element, // by putting an empty string between the tags. Yes, it's a kludge // but what'cha gonna do about it. :-) // if( flushedBytes == 0 && Arrays.binarySearch( EMPTY_ELEMENTS, s ) < 0 ) { currEl.addContent(""); } return m_currentElement; } currEl = currEl.getParentElement(); } return null; } /** * Reads the stream until it meets one of the specified * ending characters, or stream end. The ending character will be left * in the stream. */ private String readUntil( String endChars ) throws IOException { StringBuilder sb = new StringBuilder( 80 ); int ch = nextToken(); while( ch != -1 ) { if( ch == '\\' ) { ch = nextToken(); if( ch == -1 ) { break; } } else { if( endChars.indexOf((char)ch) != -1 ) { pushBack( ch ); break; } } sb.append( (char) ch ); ch = nextToken(); } return sb.toString(); } /** * Reads the stream while the characters that have been specified are * in the stream, returning then the result as a String. */ private String readWhile( String endChars ) throws IOException { StringBuilder sb = new StringBuilder( 80 ); int ch = nextToken(); while( ch != -1 ) { if( endChars.indexOf((char)ch) == -1 ) { pushBack( ch ); break; } sb.append( (char) ch ); ch = nextToken(); } return sb.toString(); } private JSPWikiMarkupParser m_cleanTranslator; /** * Does a lazy init. Otherwise, we would get into a situation * where HTMLRenderer would try and boot a TranslatorReader before * the TranslatorReader it is contained by is up. */ private JSPWikiMarkupParser getCleanTranslator() { if( m_cleanTranslator == null ) { WikiContext dummyContext = new WikiContext( m_engine, m_context.getHttpRequest(), m_context.getPage() ); m_cleanTranslator = new JSPWikiMarkupParser( dummyContext, null ); m_cleanTranslator.m_allowHTML = true; } return m_cleanTranslator; } /** * Modifies the "hd" parameter to contain proper values. Because * an "id" tag may only contain [a-zA-Z0-9:_-], we'll replace the * % after url encoding with '_'. * <p> * Counts also duplicate headings (= headings with similar name), and * attaches a counter. */ private String makeHeadingAnchor( String baseName, String title, Heading hd ) { hd.m_titleText = title; title = MarkupParser.wikifyLink( title ); hd.m_titleSection = m_engine.encodeName(title); if( m_titleSectionCounter.containsKey( hd.m_titleSection ) ) { Integer count = m_titleSectionCounter.get( hd.m_titleSection ); count = count + 1; m_titleSectionCounter.put( hd.m_titleSection, count ); hd.m_titleSection += "-" + count; } else { m_titleSectionCounter.put( hd.m_titleSection, 1 ); } hd.m_titleAnchor = "section-"+m_engine.encodeName(baseName)+ "-"+hd.m_titleSection; hd.m_titleAnchor = hd.m_titleAnchor.replace( '%', '_' ); hd.m_titleAnchor = hd.m_titleAnchor.replace( '/', '_' ); return hd.m_titleAnchor; } private String makeSectionTitle( String title ) { title = title.trim(); String outTitle; try { JSPWikiMarkupParser dtr = getCleanTranslator(); dtr.setInputReader( new StringReader(title) ); CleanTextRenderer ctt = new CleanTextRenderer(m_context, dtr.parse()); outTitle = ctt.getString(); } catch( IOException e ) { log.fatal("CleanTranslator not working", e); throw new InternalWikiException("CleanTranslator not working as expected, when cleaning title"+ e.getMessage() ); } return outTitle; } /** * Returns XHTML for the heading. * * @param level The level of the heading. @see Heading * @param title the title for the heading * @param hd a List to which heading should be added * @return An Element containing the heading */ public Element makeHeading( int level, String title, Heading hd ) { Element el = null; String pageName = m_context.getPage().getName(); String outTitle = makeSectionTitle( title ); hd.m_level = level; switch( level ) { case Heading.HEADING_SMALL: el = new Element("h4").setAttribute("id",makeHeadingAnchor( pageName, outTitle, hd )); break; case Heading.HEADING_MEDIUM: el = new Element("h3").setAttribute("id",makeHeadingAnchor( pageName, outTitle, hd )); break; case Heading.HEADING_LARGE: el = new Element("h2").setAttribute("id",makeHeadingAnchor( pageName, outTitle, hd )); break; default: throw new InternalWikiException("Illegal heading type "+level); } return el; } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -