1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.rendering.internal.renderer.xhtml

File XHTMLChainingRenderer.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

36
159
48
1
559
401
85
0.53
3.31
48
1.77

Classes

Class Line # Actions
XHTMLChainingRenderer 50 159 0% 85 4
0.983539198.4%
 

Contributing tests

This file is covered by 554 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.rendering.internal.renderer.xhtml;
21   
22    import java.util.LinkedHashMap;
23    import java.util.List;
24    import java.util.Map;
25   
26    import org.xwiki.rendering.internal.renderer.xhtml.image.XHTMLImageRenderer;
27    import org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkRenderer;
28    import org.xwiki.rendering.listener.Format;
29    import org.xwiki.rendering.listener.HeaderLevel;
30    import org.xwiki.rendering.listener.ListType;
31    import org.xwiki.rendering.listener.MetaData;
32    import org.xwiki.rendering.listener.chaining.BlockStateChainingListener;
33    import org.xwiki.rendering.listener.chaining.BlockStateChainingListener.Event;
34    import org.xwiki.rendering.listener.chaining.EmptyBlockChainingListener;
35    import org.xwiki.rendering.listener.chaining.ListenerChain;
36    import org.xwiki.rendering.listener.chaining.MetaDataStateChainingListener;
37    import org.xwiki.rendering.listener.reference.ResourceReference;
38    import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
39    import org.xwiki.rendering.renderer.printer.WikiPrinter;
40    import org.xwiki.rendering.renderer.printer.XHTMLWikiPrinter;
41    import org.xwiki.rendering.syntax.Syntax;
42    import org.xwiki.rendering.syntax.SyntaxType;
43   
44    /**
45    * Convert listener events to XHTML.
46    *
47    * @version $Id: a63a17951449f51d0ab1649a86b8c2e900bddbeb $
48    * @since 1.8RC1
49    */
 
50    public class XHTMLChainingRenderer extends AbstractChainingPrintRenderer
51    {
52    private XHTMLLinkRenderer linkRenderer;
53   
54    private XHTMLImageRenderer imageRenderer;
55   
56    private XHTMLWikiPrinter xhtmlWikiPrinter;
57   
58    /**
59    * @param linkRenderer the object to render link events into XHTML. This is done so that it's pluggable because link
60    * rendering depends on how the underlying system wants to handle it. For example for XWiki we check if
61    * the document exists, we get the document URL, etc.
62    * @param imageRenderer the object to render image events into XHTML. This is done so that it's pluggable because
63    * image rendering depends on how the underlying system wants to handle it. For example for XWiki we
64    * check if the image exists as a document attachments, we get its URL, etc.
65    * @param listenerChain the chain of listener filters used to compute various states
66    */
 
67  19600 toggle public XHTMLChainingRenderer(XHTMLLinkRenderer linkRenderer, XHTMLImageRenderer imageRenderer,
68    ListenerChain listenerChain)
69    {
70  19599 setListenerChain(listenerChain);
71   
72  19599 this.linkRenderer = linkRenderer;
73  19597 this.imageRenderer = imageRenderer;
74    }
75   
76    // State
77   
 
78  48138 toggle protected BlockStateChainingListener getBlockState()
79    {
80  48138 return (BlockStateChainingListener) getListenerChain().getListener(BlockStateChainingListener.class);
81    }
82   
 
83  812 toggle protected EmptyBlockChainingListener getEmptyBlockState()
84    {
85  812 return (EmptyBlockChainingListener) getListenerChain().getListener(EmptyBlockChainingListener.class);
86    }
87   
 
88  1296 toggle protected MetaDataStateChainingListener getMetaDataState()
89    {
90  1296 return (MetaDataStateChainingListener) getListenerChain().getListener(MetaDataStateChainingListener.class);
91    }
92   
93    // Printer
94   
 
95  19599 toggle @Override
96    protected void pushPrinter(WikiPrinter wikiPrinter)
97    {
98  19600 super.pushPrinter(wikiPrinter);
99  19599 getXHTMLWikiPrinter().setWikiPrinter(getPrinter());
100    }
101   
 
102  0 toggle @Override
103    protected void popPrinter()
104    {
105  0 super.popPrinter();
106  0 getXHTMLWikiPrinter().setWikiPrinter(getPrinter());
107    }
108   
 
109  109795 toggle protected XHTMLWikiPrinter getXHTMLWikiPrinter()
110    {
111  109795 if (this.xhtmlWikiPrinter == null) {
112  19466 this.xhtmlWikiPrinter = new XHTMLWikiPrinter(getPrinter());
113    }
114  109796 return this.xhtmlWikiPrinter;
115    }
116   
117    // Events
118   
 
119  1539 toggle @Override
120    public void beginGroup(Map<String, String> parameters)
121    {
122  1539 Map<String, String> clonedParameters = new LinkedHashMap<String, String>();
123  1539 clonedParameters.putAll(parameters);
124  1539 getXHTMLWikiPrinter().printXMLStartElement("div", clonedParameters);
125    }
126   
 
127  1539 toggle @Override
128    public void endGroup(Map<String, String> parameters)
129    {
130  1539 getXHTMLWikiPrinter().printXMLEndElement("div");
131    }
132   
 
133  4872 toggle @Override
134    public void beginFormat(Format format, Map<String, String> parameters)
135    {
136  4872 switch (format) {
137  386 case BOLD:
138  386 getXHTMLWikiPrinter().printXMLStartElement("strong");
139  386 break;
140  99 case ITALIC:
141  99 getXHTMLWikiPrinter().printXMLStartElement("em");
142  99 break;
143  6 case STRIKEDOUT:
144  6 getXHTMLWikiPrinter().printXMLStartElement("del");
145  6 break;
146  4 case UNDERLINED:
147  4 getXHTMLWikiPrinter().printXMLStartElement("ins");
148  4 break;
149  5 case SUPERSCRIPT:
150  5 getXHTMLWikiPrinter().printXMLStartElement("sup");
151  5 break;
152  5 case SUBSCRIPT:
153  5 getXHTMLWikiPrinter().printXMLStartElement("sub");
154  5 break;
155  4 case MONOSPACE:
156  4 getXHTMLWikiPrinter().printXMLStartElement("tt");
157  4 break;
158  4363 case NONE:
159  4363 break;
160    }
161  4872 if (!parameters.isEmpty()) {
162  4373 getXHTMLWikiPrinter().printXMLStartElement("span", parameters);
163    }
164    }
165   
 
166  4872 toggle @Override
167    public void endFormat(Format format, Map<String, String> parameters)
168    {
169  4872 if (!parameters.isEmpty()) {
170  187 getXHTMLWikiPrinter().printXMLEndElement("span");
171    }
172  4872 switch (format) {
173  386 case BOLD:
174  386 getXHTMLWikiPrinter().printXMLEndElement("strong");
175  386 break;
176  99 case ITALIC:
177  99 getXHTMLWikiPrinter().printXMLEndElement("em");
178  99 break;
179  6 case STRIKEDOUT:
180  6 getXHTMLWikiPrinter().printXMLEndElement("del");
181  6 break;
182  4 case UNDERLINED:
183  4 getXHTMLWikiPrinter().printXMLEndElement("ins");
184  4 break;
185  5 case SUPERSCRIPT:
186  5 getXHTMLWikiPrinter().printXMLEndElement("sup");
187  5 break;
188  5 case SUBSCRIPT:
189  5 getXHTMLWikiPrinter().printXMLEndElement("sub");
190  5 break;
191  4 case MONOSPACE:
192  4 getXHTMLWikiPrinter().printXMLEndElement("tt");
193  4 break;
194  4363 case NONE:
195  4363 break;
196    }
197    }
198   
 
199  1253 toggle @Override
200    public void beginParagraph(Map<String, String> parameters)
201    {
202  1253 getXHTMLWikiPrinter().printXMLStartElement("p", parameters);
203    }
204   
 
205  1253 toggle @Override
206    public void endParagraph(Map<String, String> parameters)
207    {
208  1253 getXHTMLWikiPrinter().printXMLEndElement("p");
209    }
210   
 
211  405 toggle @Override
212    public void onNewLine()
213    {
214  405 getXHTMLWikiPrinter().printXMLElement("br");
215    }
216   
 
217  812 toggle @Override
218    public void beginLink(ResourceReference reference, boolean freestanding, Map<String, String> parameters)
219    {
220    // Ensure the link renderer is using the latest printer since the original printer used could have been
221    // superseded by another one in the printer stack.
222  812 this.linkRenderer.setXHTMLWikiPrinter(getXHTMLWikiPrinter());
223   
224    // If the ResourceReference doesn't have a base reference specified, then look for one in previously sent
225    // events (it's sent in begin/endMetaData events).
226  812 List<String> baseReferences = reference.getBaseReferences();
227  812 if (baseReferences.isEmpty()) {
228  811 reference.addBaseReferences(getMetaDataState().<String>getAllMetaData(MetaData.BASE));
229    }
230   
231  812 this.linkRenderer.beginLink(reference, freestanding, parameters);
232    }
233   
 
234  812 toggle @Override
235    public void endLink(ResourceReference reference, boolean freestanding, Map<String, String> parameters)
236    {
237  812 this.linkRenderer.setHasLabel(!getEmptyBlockState().isCurrentContainerBlockEmpty());
238  812 this.linkRenderer.endLink(reference, freestanding, parameters);
239    }
240   
 
241  519 toggle @Override
242    public void beginHeader(HeaderLevel level, String id, Map<String, String> parameters)
243    {
244  519 Map<String, String> attributes = new LinkedHashMap<String, String>();
245   
246  519 attributes.put("id", id);
247  519 attributes.putAll(parameters);
248   
249    // Section editing feature:
250    // In order for the UI side to be able to add a section edit button we need to provide some information to it
251    // and especially we need to tell it if the header was a header generated by a macro or not. The reason is
252    // that macro-generated headers should not be editable by the user.
253    // TODO: In the future it's possible that we'll want this kind of behavior implemented using a Transformation.
254    // If we decide this then remove this code.
255  519 if (getBlockState().isInMacro()) {
256  429 String classAttributeName = "class";
257  429 String classValue = attributes.get(classAttributeName);
258  429 String newClassValue = "wikigeneratedheader";
259  429 if (classValue == null) {
260  416 classValue = newClassValue;
261    } else {
262  13 classValue = classValue.trim() + " " + newClassValue;
263    }
264  429 attributes.put(classAttributeName, classValue);
265    }
266   
267  519 getXHTMLWikiPrinter().printXMLStartElement("h" + level.getAsInt(), attributes);
268    // We generate a span so that CSS rules have a hook to perform some magic that wouldn't work on just a H
269    // element. Like some IE6 magic and others.
270  519 getXHTMLWikiPrinter().printXMLStartElement("span");
271    }
272   
 
273  519 toggle @Override
274    public void endHeader(HeaderLevel level, String id, Map<String, String> parameters)
275    {
276  519 getXHTMLWikiPrinter().printXMLEndElement("span");
277  519 getXHTMLWikiPrinter().printXMLEndElement("h" + level.getAsInt());
278    }
279   
 
280  33580 toggle @Override
281    public void onWord(String word)
282    {
283  33580 getXHTMLWikiPrinter().printXML(word);
284    }
285   
 
286  16112 toggle @Override
287    public void onSpace()
288    {
289    // The XHTML printer will decide whether to print a normal space or a &nbsp;
290  16112 getXHTMLWikiPrinter().printSpace();
291    }
292   
 
293  2981 toggle @Override
294    public void onSpecialSymbol(char symbol)
295    {
296  2981 getXHTMLWikiPrinter().printXML("" + symbol);
297    }
298   
 
299  1367 toggle @Override
300    public void beginList(ListType type, Map<String, String> parameters)
301    {
302  1367 if (type == ListType.BULLETED) {
303  1333 getXHTMLWikiPrinter().printXMLStartElement("ul", parameters);
304    } else {
305  34 getXHTMLWikiPrinter().printXMLStartElement("ol", parameters);
306    }
307    }
308   
 
309  4408 toggle @Override
310    public void beginListItem()
311    {
312  4408 getXHTMLWikiPrinter().printXMLStartElement("li");
313    }
314   
 
315  1367 toggle @Override
316    public void endList(ListType type, Map<String, String> parameters)
317    {
318  1367 if (type == ListType.BULLETED) {
319  1333 getXHTMLWikiPrinter().printXMLEndElement("ul");
320    } else {
321  34 getXHTMLWikiPrinter().printXMLEndElement("ol");
322    }
323    }
324   
 
325  4408 toggle @Override
326    public void endListItem()
327    {
328  4408 getXHTMLWikiPrinter().printXMLEndElement("li");
329    }
330   
 
331  3 toggle @Override
332    public void onId(String name)
333    {
334    // Don't use the "name" attribute (see http://www.w3.org/TR/html4/struct/links.html#h-12.2.3).
335    // If the id s in a paragraph use <span id="..."> and if in a standalone block then use
336    // <div id="...">.
337  3 if (getBlockState().isInLine()) {
338    // Note: We're using <span><span/> and not <span/> since some browsers do not support the
339    // <span/> syntax (FF3) when the content type is set to HTML instead of XHTML.
340  2 getXHTMLWikiPrinter().printXMLStartElement("span", new String[][] { { "id", name } });
341  2 getXHTMLWikiPrinter().printXMLEndElement("span");
342    } else {
343  1 getXHTMLWikiPrinter().printXMLStartElement("div", new String[][] { { "id", name } });
344  1 getXHTMLWikiPrinter().printXMLEndElement("div");
345    }
346    }
347   
 
348  14 toggle @Override
349    public void onHorizontalLine(Map<String, String> parameters)
350    {
351  14 getXHTMLWikiPrinter().printXMLElement("hr", parameters);
352    }
353   
 
354  25 toggle @Override
355    public void onVerbatim(String content, boolean inline, Map<String, String> parameters)
356    {
357  25 if (inline) {
358    // Note: We generate a tt element rather than a pre element since pre elements cannot be located inside
359    // paragraphs for example. There also no tag in XHTML that has a semantic of preserving inline content so
360    // tt is the closed to pre for inline.
361    // The class is what is expected by wikimodel to understand the tt as meaning a verbatim and not a Monospace
362    // element.
363  13 getXHTMLWikiPrinter().printXMLStartElement("tt", new String[][] { { "class", "wikimodel-verbatim" } });
364  13 getXHTMLWikiPrinter().printXML(content);
365  13 getXHTMLWikiPrinter().printXMLEndElement("tt");
366    } else {
367  12 getXHTMLWikiPrinter().printXMLStartElement("pre", parameters);
368  12 getXHTMLWikiPrinter().printXML(content);
369  12 getXHTMLWikiPrinter().printXMLEndElement("pre");
370    }
371    }
372   
 
373  140 toggle @Override
374    public void onEmptyLines(int count)
375    {
376    // We need to use a special tag for empty lines since in XHTML the BR tag cannot be used outside of content
377    // tags.
378    // Note: We're using <div><div/> and not <div/> since some browsers do not support the <div/> syntax (FF3)
379    // when the content type is set to HTML instead of XHTML.
380  305 for (int i = 0; i < count; ++i) {
381  165 getXHTMLWikiPrinter().printXMLStartElement("div", new String[][] { { "class", "wikimodel-emptyline" } });
382  165 getXHTMLWikiPrinter().printXMLEndElement("div");
383    }
384    }
385   
386    /**
387    * {@inheritDoc}
388    *
389    * @since 2.0RC1
390    */
 
391  48 toggle @Override
392    public void beginDefinitionList(Map<String, String> parameters)
393    {
394  48 getXHTMLWikiPrinter().printXMLStartElement("dl", parameters);
395    }
396   
397    /**
398    * {@inheritDoc}
399    *
400    * @since 2.0RC1
401    */
 
402  48 toggle @Override
403    public void endDefinitionList(Map<String, String> parameters)
404    {
405  48 getXHTMLWikiPrinter().printXMLEndElement("dl");
406    }
407   
 
408  107 toggle @Override
409    public void beginDefinitionTerm()
410    {
411  107 getXHTMLWikiPrinter().printXMLStartElement("dt");
412    }
413   
 
414  112 toggle @Override
415    public void beginDefinitionDescription()
416    {
417  112 getXHTMLWikiPrinter().printXMLStartElement("dd");
418    }
419   
 
420  107 toggle @Override
421    public void endDefinitionTerm()
422    {
423  107 getXHTMLWikiPrinter().printXMLEndElement("dt");
424    }
425   
 
426  112 toggle @Override
427    public void endDefinitionDescription()
428    {
429  112 getXHTMLWikiPrinter().printXMLEndElement("dd");
430    }
431   
 
432  16 toggle @Override
433    public void beginQuotation(Map<String, String> parameters)
434    {
435  16 if (getBlockState().isInQuotationLine()) {
436  8 getXHTMLWikiPrinter().printXMLEndElement("p");
437    }
438   
439  16 getXHTMLWikiPrinter().printXMLStartElement("blockquote", parameters);
440   
441  16 getXHTMLWikiPrinter().printXMLStartElement("p");
442    }
443   
 
444  16 toggle @Override
445    public void endQuotation(Map<String, String> parameters)
446    {
447  16 getXHTMLWikiPrinter().printXMLEndElement("p");
448   
449  16 getXHTMLWikiPrinter().printXMLEndElement("blockquote");
450   
451  16 if (getBlockState().isInQuotationLine()) {
452  8 getXHTMLWikiPrinter().printXMLStartElement("p");
453    }
454    }
455   
 
456  24 toggle @Override
457    public void beginQuotationLine()
458    {
459    // Send a new line if the previous event was endQuotationLine since we need to separate each quotation line
460    // or they'll printed next to each other and not on a new line each.
461  24 if (getBlockState().isInQuotation() && getBlockState().getPreviousEvent() == Event.QUOTATION_LINE) {
462  8 onNewLine();
463    }
464    }
465   
 
466  59 toggle @Override
467    public void beginTable(Map<String, String> parameters)
468    {
469  59 getXHTMLWikiPrinter().printXMLStartElement("table", parameters);
470    }
471   
 
472  156 toggle @Override
473    public void beginTableRow(Map<String, String> parameters)
474    {
475  156 getXHTMLWikiPrinter().printXMLStartElement("tr", parameters);
476    }
477   
 
478  270 toggle @Override
479    public void beginTableCell(Map<String, String> parameters)
480    {
481  270 getXHTMLWikiPrinter().printXMLStartElement("td", parameters);
482    }
483   
 
484  110 toggle @Override
485    public void beginTableHeadCell(Map<String, String> parameters)
486    {
487    // Find proper scope attribute value
488  110 Map<String, String> parametersWithScope;
489  110 if (!parameters.containsKey("scope")) {
490  53 parametersWithScope = new LinkedHashMap<String, String>(parameters);
491   
492  53 if (getBlockState().getCellRow() == 0 || getBlockState().getCellCol() > 0) {
493  49 parametersWithScope.put("scope", "col");
494    } else {
495  4 parametersWithScope.put("scope", "row");
496    }
497    } else {
498  57 parametersWithScope = parameters;
499    }
500   
501    // Write th element
502  110 getXHTMLWikiPrinter().printXMLStartElement("th", parametersWithScope);
503    }
504   
 
505  59 toggle @Override
506    public void endTable(Map<String, String> parameters)
507    {
508  59 getXHTMLWikiPrinter().printXMLEndElement("table");
509    }
510   
 
511  156 toggle @Override
512    public void endTableRow(Map<String, String> parameters)
513    {
514  156 getXHTMLWikiPrinter().printXMLEndElement("tr");
515    }
516   
 
517  270 toggle @Override
518    public void endTableCell(Map<String, String> parameters)
519    {
520  270 getXHTMLWikiPrinter().printXMLEndElement("td");
521    }
522   
 
523  110 toggle @Override
524    public void endTableHeadCell(Map<String, String> parameters)
525    {
526  110 getXHTMLWikiPrinter().printXMLEndElement("th");
527    }
528   
529    /**
530    * {@inheritDoc}
531    *
532    * @since 2.5RC1
533    */
 
534  486 toggle @Override
535    public void onImage(ResourceReference reference, boolean freestanding, Map<String, String> parameters)
536    {
537    // Ensure the image renderer is using the latest printer since the original printer used could have been
538    // superseded by another one in the printer stack.
539  486 this.imageRenderer.setXHTMLWikiPrinter(getXHTMLWikiPrinter());
540   
541    // If the ResourceReference doesn't have a base reference specified, then look for one in previously sent
542    // events (it's sent in begin/endMetaData events).
543  486 List<String> baseReferences = reference.getBaseReferences();
544  486 if (baseReferences.isEmpty()) {
545  485 reference.addBaseReferences(getMetaDataState().<String>getAllMetaData(MetaData.BASE));
546    }
547   
548  486 this.imageRenderer.onImage(reference, freestanding, parameters);
549    }
550   
 
551  6614 toggle @Override
552    public void onRawText(String text, Syntax syntax)
553    {
554    // Directly inject the HTML content in the wiki printer (bypassing the XHTML printer)
555  6614 if ((syntax.getType() == SyntaxType.XHTML) || (syntax.getType() == SyntaxType.HTML)) {
556  6614 getXHTMLWikiPrinter().printRaw(text);
557    }
558    }
559    }