Wiki source code of Skin Extension Script API

Last modified by Eleni Cojocariu on 2026/09/30 18:26

Hide last authors
Eleni Cojocariu 2.1 1 The calls that pull a skin extension into the response being built, from Velocity and from Java. Pulling is what puts the generated ##script## or ##link## element on the page; [[Skin Extensions>>doc:documentation.xs.dev.skin-extensions.WebHome]] describes what happens on either side of it.
2
3 == Pulling from Velocity ==
4
5 Seven pull methods are exposed to Velocity, one per source the code can come from.
6
7 |=Call|=Where the code comes from
8 |##$xwiki.jsx.use('Space.Page')##|An ##XWiki.JavaScriptExtension## object on a wiki page.
9 |##$xwiki.ssx.use('Space.Page')##|An ##XWiki.StyleSheetExtension## object on a wiki page.
10 |##$xwiki.jsfx.use('path/to/file.js')##|A JavaScript file of the current skin, or of the ##resources## folder of the web application.
11 |##$xwiki.ssfx.use('path/to/file.css')##|The same, for a style sheet.
12 |##$xwiki.jsrx.use('path/to/file.js')##|A JavaScript file inside a JAR, in ##WEB-INF/lib## or brought in by an installed extension.
13 |##$xwiki.ssrx.use('path/to/file.css')##|The same, for a style sheet.
14 |##$xwiki.linkx.use($url, $parameters)##|Any address. The parameters become the attributes of the generated ##link## element rather than a query string.
15
16 The argument of ##jsx## and ##ssx## is the **reference of the wiki page** holding the object, not the object's ##name## field, which the plugin ignores entirely (see [[Skin Extension Object Fields>>doc:documentation.xs.dev.skin-extensions.object-fields.WebHome]]):
17
18 {{code language="velocity"}}
19 {{velocity}}
20 #set ($discard = $xwiki.ssx.use('My.CSS'))
21 #set ($discard = $xwiki.jsx.use('My.JavaScript'))
22 {{/velocity}}
23 {{/code}}
24
25 ##linkx## exists for the files an installed extension ships rather than the wiki, a [[WebJar>>doc:extensions:Extension.WebJars Integration]] above all:
26
27 {{code language="velocity"}}
28 #set ($discard = $xwiki.linkx.use($services.webjars.url('artifact-id', 'path/to/file.css'),
29 {'type': 'text/css', 'rel': 'stylesheet'}))
30 {{/code}}
31
32 ##jsfx## and ##ssfx## accept a boolean in place of the map, ##$xwiki.jsfx.use('path/to/file.js', true)##, which is the same as passing ##{'forceSkinAction': true}##.
33
34 Only ##jsx## and ##ssx## read the ##use## field of an object. A skin file, a file inside a JAR and a link are loaded by an explicit pull and by nothing else.
35
36 == Parameters of use() ==
37
38 All seven take a map as second argument. For six of them every entry is appended to the generated URL as ##&key=value##, key and value both URL encoded so that a value cannot break out of the element being written; ##linkx## is the exception named above. Four names have a meaning of their own: three that are passed, and ##language##, which the plugins add by themselves.
39
40 |=Parameter|=Applies to|=Default|=What it does
41 |##language##|##jsx## and ##ssx##|the locale of the request|Added on its own, so the translations the extension uses resolve in the reader's language.
42 |##minify##|##jsx##, ##ssx##, ##jsrx##, ##ssrx##|##true##|##false## serves the source unminified. On ##jsfx## and ##ssfx## it takes effect only together with ##forceSkinAction##.
43 |##forceSkinAction##|##jsfx## and ##ssfx##|##false##|Routes the file through the ##skin## action, which evaluates it as Velocity. Read and then dropped, never appended to the URL.
44 |##defer##|the three JavaScript extensions|##true##|Puts ##defer='defer'## on the generated ##script## element. The instance default is the ##xwiki.plugins.skinx.deferred.default## property of ##xwiki.cfg##.
45
46 Any other entry of the map arrives at the extension as a request parameter, which is how a parsed extension is given something to work with; see [[Generate Skin Extension Content with Velocity>>doc:documentation.xs.dev.skin-extensions.velocity.WebHome]].
47
48 While debugging, adding ##minify=false## to the query string of the page being read is enough: the plugins copy it onto every extension URL of that page, so it does not have to be passed call by call. The instance-wide switch is the ##debug.minify## property of ##xwiki.properties##, ##true## by default.
49
50 == Deferred execution ==
51
52 A JavaScript extension does not hold the page up: the browser finishes parsing the document and runs the script after that. Pass ##{'defer': false}## for a script that has to run earlier.
53
54 == Pulling from Java ==
55
56 Java code injects the ##org.xwiki.skinx.SkinExtension## role under one of the seven hints:
57
58 {{code language="java"}}
59 @Inject
60 @Named("jsx")
61 private SkinExtension jsx;
62
63 // ...
64
65 this.jsx.use("My.JavaScript");
66 {{/code}}
67
68 Each of those components is a thin wrapper that finds the matching plugin by its hint and forwards the call. It is the only supported way in from Java: a pull made any other way is lost when a cached asynchronous block is rendered a second time.

Get Connected