Wiki source code of Skin Extension Script API
Last modified by Eleni Cojocariu on 2026/09/30 18:26
Hide last authors
| author | version | line-number | content |
|---|---|---|---|
![]() |
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. |
