Wiki source code of Extending XWiki Rendering
Last modified by Vincent Massol on 2024/03/27 13:35
Show last authors
author | version | line-number | content |
---|---|---|---|
1 | {{box cssClass="floatinginfobox" title="**Contents**"}} | ||
2 | {{toc/}} | ||
3 | {{/box}} | ||
4 | |||
5 | = Adding a new Syntax = | ||
6 | |||
7 | You have 2 possibilities: | ||
8 | |||
9 | * You might want to add the ability to write page content using a new input Syntax. In this case you'll need to write a Parser. | ||
10 | * or you might want to be able to render page content in a new output Syntax. In this case you'll need to write a Renderer. | ||
11 | |||
12 | == Adding a Parser == | ||
13 | |||
14 | To add a Parser, simply implement the Parser interface and register it as a component against the Component Manager. | ||
15 | |||
16 | Example: | ||
17 | |||
18 | {{code language="java"}} | ||
19 | public class MyParser implements Parser | ||
20 | { | ||
21 | private static final Syntax SYNTAX = new Syntax(new SyntaxType("mysyntax", "My Syntax"), "1.0"); | ||
22 | |||
23 | public Syntax getSyntax() | ||
24 | { | ||
25 | return SYNTAX; | ||
26 | } | ||
27 | |||
28 | public XDOM parse(Reader source) throws ParseException | ||
29 | { | ||
30 | XDOM xdom = new XDOM(Collections.singletonList(new WordBlock("amazing"))); | ||
31 | return xdom; | ||
32 | } | ||
33 | } | ||
34 | {{/code}} | ||
35 | |||
36 | In practice how the contributed Parser is implemented is left to the implementer. | ||
37 | |||
38 | More precisely we support several strategies: | ||
39 | |||
40 | * Using {{scm project="xwiki-rendering" path="xwiki-rendering-wikimodel"}}WikiModel{{/scm}}. Historically this project was used as an external dependency of XWiki Rendering and was providing Parser implementations for various syntaxes. We have coded a {{scm project="xwiki-rendering" path="xwiki-rendering-syntax-wikimodel"}}WikiModel bridge{{/scm}} to convert WikiModel events to XWiki Rendering events. However since WikiModel wasn't really active and maintained (except by a few XWiki Rendering developers), we decided to fork the WikiModel's sources in the XWiki Rendering sources in the {{scm project="xwiki-rendering" path="xwiki-rendering-wikimodel"}}xwiki-rendering-wikimodel{{/scm}} module. The goal in the future is to refactor this module and spread the code in various existing modules. For example this module uses JavaCC to generate Java source from grammar files. At the moment the {{scm project="xwiki-rendering" path="xwiki-rendering-wikimodel/src/main/javacc"}}JavaCC grammars{{/scm}} are still located in that module but the plan is to move them to the various ##xwiki-rendering-syntax-XXX## modules. | ||
41 | ** Examples of syntaxes using this strategy: XWiki 2.x syntaxes, Confluence syntax, MediaWiki syntax | ||
42 | * We have also coded a [[Doxia>>https://maven.apache.org/doxia/]] {{scm project="xwiki-rendering" path="xwiki-rendering-rendering-doxia"}}bridge{{/scm}} to allow using Doxia Parsers (the bridge converts Doxia events into XWiki Rendering events). | ||
43 | ** Examples of syntaxes using this strategy: Docbook, TeX | ||
44 | * Some syntaxes use specific third-party Parsers. | ||
45 | ** Examples of syntaxes using this strategy: Markdown (which uses [[PegDown>>https://github.com/sirthias/pegdown]]). | ||
46 | * Last, parsing code can be implemented directly in the XWiki Rendering syntax module. | ||
47 | ** Examples of syntaxes using this strategy: None at this stage but in the future we'll probably move the full HTML syntax parsing code in the ##xwiki-rendering-syntax-xhtml## module (the parsing code is currently mostly located in ##xwiki-rendering-wikimodel## and a bit in ##xwiki-rendering-syntax-xhtml## too). | ||
48 | |||
49 | Make sure to check {{scm project="xwiki-rendering" path="xwiki-rendering-syntaxes"}}existing parser implementations{{/scm}}. | ||
50 | |||
51 | == Adding a Renderer == | ||
52 | |||
53 | TODO: Add tutorial | ||
54 | |||
55 | You have to implement the [[Renderer interface>>https://github.com/xwiki/xwiki-rendering/blob/master/xwiki-rendering-api/src/main/java/org/xwiki/rendering/renderer/Renderer.java]]. | ||
56 | Examples of Renderer source code: | ||
57 | |||
58 | * {{scm project="xwiki-rendering" path="xwiki-rendering-syntaxes/xwiki-rendering-syntax-xhtml/src/main/java/org/xwiki/rendering/internal/renderer/xhtml/XHTMLRenderer.java"}}XHTML Renderer{{/scm}} | ||
59 | * {{scm project="xwiki-rendering" path="xwiki-rendering-syntaxes/xwiki-rendering-syntax-xwiki20/src/main/java/org/xwiki/rendering/internal/renderer/xwiki20/XWikiSyntaxRenderer.java"}}XWiki 2.0 Syntax Renderer{{/scm}} | ||
60 | * {{scm project="xwiki-rendering" path="xwiki-rendering-syntaxes/xwiki-rendering-syntax-event/src/main/java/org/xwiki/rendering/internal/renderer/event/EventRenderer.java"}}Events Renderer{{/scm}} | ||
61 | |||
62 | == Adding Tests == | ||
63 | |||
64 | You'll need to write tests to verify that your Parser/Renderer work fine. | ||
65 | |||
66 | There are 2 Rendering test frameworks you can use (they're both located in the ##org.xwiki.rendering:xwiki-rendering-test## module): | ||
67 | |||
68 | * The [[Rendering Test Framework>>Main.Extending.RenderingTestFramework]]: Allows to easily write tests to assert that your Parser or Renderer does the right thing. | ||
69 | * The [[Compatibility Test Suite>>Main.Extending.CompatibilityTestSuite]]: A well-known suite of commmon Tests for all Syntaxes to pass. | ||
70 | |||
71 | == Best Practices == | ||
72 | |||
73 | * ((({{version since="11.3RC1"}}There's now the concept of a Syntax Registry and new Syntaxes are expected to register themselves in that registry. This is achieved by implementing the ##Provider<List<Syntax>>## component role. For example to register a ##html/4.01## syntax you'd write: | ||
74 | |||
75 | {{code language="java"}} | ||
76 | @Component | ||
77 | @Named("html/4.01") | ||
78 | @Singleton | ||
79 | public class HTML401SyntaxProvider implements Provider<List<Syntax>> | ||
80 | { | ||
81 | /** | ||
82 | * HTML syntax type. | ||
83 | */ | ||
84 | public static final SyntaxType HTML = new SyntaxType("html", "HTML"); | ||
85 | |||
86 | /** | ||
87 | * HTML 4.01 syntax. | ||
88 | */ | ||
89 | public static final Syntax HTML_4_01 = new Syntax(HTML, "4.01"); | ||
90 | |||
91 | @Override | ||
92 | public List<Syntax> get() | ||
93 | { | ||
94 | return Collections.singletonList(HTML_4_01); | ||
95 | } | ||
96 | } | ||
97 | {{/code}} | ||
98 | {{/version}}))) | ||
99 | |||
100 | = Adding a new Macro = | ||
101 | |||
102 | Follow the [[Macro Tutorial>>ExtendingMacro]]. | ||
103 | |||
104 | = Adding a new Transformation = | ||
105 | |||
106 | To create a Transformation, create a Component implementing the ##org.xwiki.rendering.transformation.Transformation## interface. To make it even easier you can simply extend ##org.xwiki.rendering.transformation.AbstractTransformation##. | ||
107 | |||
108 | Example: | ||
109 | |||
110 | {{code language="java"}} | ||
111 | @Component | ||
112 | @Named("wikiword") | ||
113 | @Singleton | ||
114 | public class WikiWordTransformation extends AbstractTransformation | ||
115 | { | ||
116 | /** | ||
117 | * Regex Pattern to recognize a WikiWord. | ||
118 | */ | ||
119 | private static final Pattern WIKIWORD_PATTERN = Pattern.compile( | ||
120 | "\\p{javaUpperCase}+\\p{javaLowerCase}+(\\p{javaUpperCase}\\p{javaLowerCase}*)+"); | ||
121 | |||
122 | /** | ||
123 | * Used to filter protected blocks (code macro marker block, etc). | ||
124 | */ | ||
125 | private ProtectedBlockFilter filter = new ProtectedBlockFilter(); | ||
126 | |||
127 | @Override | ||
128 | public void transform(Block block, TransformationContext transformationContext) throws TransformationException | ||
129 | { | ||
130 | // Find all Word blocks and for each of them check if they're a wiki word or not | ||
131 | for (WordBlock wordBlock : this.filter.getChildrenByType(block, WordBlock.class, true)) { | ||
132 | Matcher matcher = WIKIWORD_PATTERN.matcher(wordBlock.getWord()); | ||
133 | if (matcher.matches()) { | ||
134 | ResourceReference linkReference = new DocumentResourceReference(wordBlock.getWord()); | ||
135 | wordBlock.getParent().replaceChild(new LinkBlock(wordBlock.getChildren(), linkReference, false), | ||
136 | wordBlock); | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | {{/code}} | ||
142 | |||
143 | Check out the [[full code with tests>>https://github.com/xwiki/xwiki-rendering/tree/master/xwiki-rendering-transformations/xwiki-rendering-transformation-wikiword]] | ||
144 | |||
145 | = Adding a new Link Type = | ||
146 | |||
147 | When using the XWiki Syntax 2.1, it's possible to extend the link syntax. The generic link syntax is: ##{{{[[label>>referenceType:referencePath]]}}}## and it's possible to add new ##referenceType##. This is a several step process: | ||
148 | |||
149 | * Implement a component with the ##org.xwiki.rendering.parser.ResourceReferenceTypeParser## role. This is used to convert from a String to a ResourceReference. Here's is the source code for {{scm project="xwiki-rendering" path="xwiki-rendering-api/src/main/java/org/xwiki/rendering/internal/parser/reference/type"}}current implementations{{/scm}}. | ||
150 | * Implement a component with the ##org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkTypeRenderer## role. This is used when rendering a link (i.e. a ResourceReference) into XHTML. Here's is the source code for {{scm project="xwiki-rendering" path="xwiki-rendering-syntaxes/xwiki-rendering-syntax-xhtml/src/main/java/org/xwiki/rendering/internal/renderer/xhtml/link"}}current implementations{{/scm}}. | ||
151 | |||
152 | You can also [[configure the WYSIWYG editor to be able to use the new Link Type>>extensions:Extension.CKEditor Integration.Customization.WebHome#HAddanewLinkType]]. | ||
153 | |||
154 | = Adding a new Image Type = | ||
155 | |||
156 | When using the XWiki Syntax 2.1 and starting with XWiki 5.4, it's possible to extend the image syntax. The generic image syntax is: ##{{{[[image:referenceType:referencePath]]}}}## and it's possible to add new ##referenceType##. This is a several step process: | ||
157 | |||
158 | * Implement a component with the ##org.xwiki.rendering.parser.ResourceReferenceTypeParser## role. This is used to convert from a String to a ResourceReference. Here's is the source code for {{scm project="xwiki-rendering" path="xwiki-rendering-api/src/main/java/org/xwiki/rendering/internal/parser/reference/type"}}current implementations{{/scm}}. | ||
159 | * Implement a component with the ##org.xwiki.rendering.internal.renderer.xhtml.image.XHTMLImageTypeRenderer## role. This is used when rendering an image (i.e. a ResourceReference) into XHTML. Here's the source code for {{scm project="xwiki-rendering" path="xwiki-rendering-syntaxes/xwiki-rendering-syntax-xhtml/src/main/java/org/xwiki/rendering/internal/renderer/xhtml/image"}}current implementations{{/scm}}. |