Artwork files for XML galleys


It took me a while to figure out how the artwork files are uploaded in OJS3. It seems that you need to a have HTML galley added first and by editing that galley, you will have the opportunity to add css and images.

Should this not be the case with XML galleys as well? At the moment I am not seeing any easy way of adding artwork for XML.

1 Like

Hi @ajnyga,

There’s a test inside templates/controllers/grid/articleGalleys/form/articleGalleyForm.tpl to check for HTML files and display a grid of dependent files in that situation:

{if $articleGalleyFile && $articleGalleyFile->getFileType()=='text/html'}

You can add this to XML files as well by changing the test:

{if $articleGalleyFile && ($articleGalleyFile->getFileType()=='text/html' || $articleGalleyFile->getFileType()=='application/xml')}

This is a little hackier than I’d like but should be fine.

The HTML article galley plugin includes some code to rewrite the markup so that artwork file URLs behave as expected; if this suits your expectations, you might want to try porting some of that code over to the lens reader plugin as well. A PR would be welcome on this, if you think you end up with something broadly useful.

Alec Smecher
Public Knowledge Project Team


Hi @asmecher

You maybe noticed the pr I did regarding this issue. Allow artwork files for XML galleys by ajnyga · Pull Request #1353 · pkp/ojs · GitHub

It was easy to add rewriting of image url’s to my embedGalley plugin. However, this is not the case with lensGalley. This is simply because lensGalley expects to have an url of a XML file.

  1. The first option I looked into was to add a new custom converter when creating the lens.js for OJS3. The eLife articles have this in their converter (lens/elife_converter.js at develop · elifesciences/lens · GitHub). However, I did not come up with any good ways of passing all the needed variables in order to form a OJS3 download url in the javascript.

  2. The second option would be, I guess, to form a new xml galley on the fly and provide an url to that. This does not seem like a good idea, I mean creating files when user opens an article.

  3. The third alternative would be to rewrite the JATS XML url’s when the article is published, or maybe add a rewrite url’s option to the galley files panel. The filter code is pretty much ready in htmlArticleGalley plugins.

Any thoughts?

Greetings @ajnyga,

XML files are live in the same directory as HTML, so apparently and relative url link to images must be the same.
Or I am missing something?

It seems that the only way of linking artwork files like images is to create a OJS download link to them, because the files are outside the web root. You can check the htmlArticleGalley to see what I mean:

That is the only way of showing artwork files that I know of, let me know if you have something different used somewhere.

XML is a variant of HTML. As I understand you can simple put this code to the lens.php or lens display.tpl, if all articles have HTML and associated with them embeded files.

I am not following now.

I upload a file as an artwork file attached to the XML galley.

I have for example this in my JATS XML
<fig id="g001"><caption><title>This is a caption</title></caption><graphic mimetype="image" xlink:href="image1.png" xlink:title="" xlink:type="simple"/></fig>

The lens plugin takes that and transforms that to HTML src="image1.png". I can not see how that would work?

The url it would get in the lens version would be something like But that does not work. Clicking that url does not open the image and it is not shown in the lens galley view.

What you need is something like Now this is easy to do in a galley plugin that first reads and then outputs the contents of the galley file, because you can filter it in the between. However, the lens plugin receives the url leading to the galley file, so basically any filtering should be done in the lens.js file. This however is difficult in this case, because you can not hard code the needed variables to the lens.js file.

I actually started to think that you would probably have to define some extra variables here: lensGalley/display.tpl at master · asmecher/lensGalley · GitHub
Maybe an array for searching and replacing the image names with the whole OJS url while renreding the XML file to HTML. This is probably what I am going to try.

But let me know if I misunderstood you somehow. Maybe you could provide an example?

I thought for XML you are trying to get URL of images embeded to HTML galley. I don’t use this approach. so don’t know how it all works.

Basically you can’t put anything inside lens.js container (div id=“container” in the result html), where is article content situated, through php or tpl file. I have tried already. Only by directly modifying lens.js.

Yes, modifying the lens.js is exactly what I am thinking of doing, or actually both the tpl file and the lens.js

The same way that document_url is defined here: lensGalley/display.tpl at master · ajnyga/lensGalley · GitHub, you could define a list of filter variables, like a list of image names that are to be replaced with the correct url. Then you just need to add a new content filter to the lens-starter package and produce a new lens.js that includes that filter. The lens-starter is specifically designed to support these kinds of special filters and it is a lot easier to make you own versions with that than try to edit the final lens.js file.

This is my current lensGalley GitHub - ajnyga/lensGalley: Galley viewer plugin integrating eLife Lens for OJS 3.0: fork using the latest develop branch of Lens it uses the latest develop branch of lens, which supports for example footnotes and I also added a Back button and support for uri element in references there with my own converter filter. I also stripped a lot of the eLife stuff from there, some of it is still left. The problem is of course the lack of support for mobile.

Very interesting.

Also want to make the changes to lens.js. Need to take a look to that starter package.

If you want to use the latest version of lens then following just the instructions in the readme there is not enough.

When you use lens-starter to create a new lens.js, it will always load the 2.0 release of lens. Because it is denifed here: lens-starter/package.json at master · elifesciences/lens-starter · GitHub

What I did was that I forked the lens repository as well and basically created a new tag for the latest release: Releases · ajnyga/lens · GitHub and used that tag in package.json file. This was actually an easy way to do some tweaks to the main conversion scripts as well. You need to change the tag in json file before running npm install.

Otherwise you can follow the instructions in lens readme.But I do think that removing this conversion script is a good idea: lens-starter/my-lens.js at master · elifesciences/lens-starter · GitHub

1 Like

Hi @asmecher and @Vitaliy

The idea I had seems to work. This is a new version of lensGalley that supports the OJS3 artwork files at least with images: GitHub - ajnyga/lensGalley: Galley viewer plugin integrating eLife Lens for OJS 3.0: fork using the latest develop branch of Lens

I am basically sending a new variable to the template here: lensGalley/ at master · ajnyga/lensGalley · GitHub which is a json_encoded list of image names to be replaced with corresponding url’s. I have used the code form htmlArticleGalley here.

That variable is defined here: lensGalley/display.tpl at master · ajnyga/lensGalley · GitHub (I was hoping to define it in not as a global variable, but could not figure out how it would work then)

I then added a new custom filter to my lens-starter package:

	this.resolveURL = function(state, url) {

		// Use absolute URL
		if (url.match(/http:\/\//)) return url;

		// Look up base url
		var baseURL = this.getBaseURL(state);

		if (baseURL) {
			return [baseURL, url].join('');
		else {

			var result = $.grep(replace_images, function(e){ return e.ojs_file === url; });

			if (result.length == 1) {
				var new_url = result[0].ojs_url
			} else {
				return url;

			return new_url;


(The original custom converter has a similar function for eLife: lens-starter/custom_converter.js at master · elifesciences/lens-starter · GitHub)

And basically with that custom filter I created a new lens.js.

The method above could be used to inject basically any OJS3 data to the lens.js, but you would of course need to create a corresponding filter as well. Edit: I guess this could be one way of localizing the lens.js UI?

1 Like

Great work!

This is certainly needed modifications. I am also wondering, will Lens render xml locale language tags? To make it multilingual.

Maybe @asmecher could share his insight on translating content in JS files (because I bet he has nothing else to comment on)? I mean, is there an example in OJS where something is getting translated in the JS file?

Because I have a feeling you can not use the ojs translation strings directly in js files, I have thought of two options:

  1. A global array ojs_translations to the tpl file. You can easily fetch the needed translations from the plugin translation files then and call them in the js file something like this: + ojs_translations[3] +
  2. Two or more separate copies of lens.js with different translations and some functionality to the tpl file to load the correct version.

Hi all,

Currently, when translated text is needed in Javascript, it’s passed via the .tpl that attaches the handler to the DOM element, e.g.: pkp-lib/index.tpl at ojs-3_0_2-0 · pkp/pkp-lib · GitHub

There’s another mechanism that’s available, which is the define_exposed PHP function; it’s like define but results in constants that are available to Javscript via the $.pkp.cons object.

Longer-term, I’d like to stop maintaining our current .xml-based translation files in favour of a more standard .po based approach, but it’s not a high priority.

@NateWr asked me a few questions a while ago and I believe was considering ways to improve upon these options along with his current Javascript foundational work – he may be able to comment.

Alec Smecher
Public Knowledge Project Team

Thanks, I will wait for Nate’s comments.

The first option you mention is pretty much the same I was thinking. The only difference being that I was thinking of defining an array in the tpl file. There are not that many strings to translate in lensGalley, so that could work fairly well.

Yeah, in the frontend I think you won’t have that many strings, so it might make sense to simply create a JSON object with the string translations you need, then pass those into Lens (I’m not familiar with Lens yet, but presume there’s some way to pass it the strings you want).

On the backend things are a bit different, because we have too many possible strings to load them with the page request. But it doesn’t sound like you need to deal with that just yet.

1 Like

Hi @NateWr and @asmecher,

What do you think about this approach?

  1. Define translation keys in locale.xml lensGalley/locale.xml at master · ajnyga/lensGalley · GitHub
  2. Load the strings to an array lensGalley/ at master · ajnyga/lensGalley · GitHub
  3. Send to template that loads lens.js lensGalley/ at master · ajnyga/lensGalley · GitHub
  4. Define as a global variable lensGalley/display.tpl at master · ajnyga/lensGalley · GitHub
  5. Call in lens.js lensGalley/lens.js at master · ajnyga/lensGalley · GitHub

That is working with the Back-button label without a problem, but maybe someone who know javascript better could say if adding several translation strings the same way would cause trouble?

edit: also tagging @Vitaliy, with that approach I think that you could localize lens.js in just a couple of hours.


Hi @ajnyga,

I’d suggest using the json_encode function inside the template, and keeping the same translation key right through from XML to JS rather than introducing another set of symbolic names – that way you can just do something like this in the PHP…

$templateMgr->assign('translationStrings', array_combine($keys = array(
        ...other keys here...
    ), $keys)

…then move the JSON encoding into the template file, similar to this example, but using instead…

cancelConfirmText: {$translationStrings|json_encode}

Generally we try to keep Javascript out of the template files, so I’d suggest attaching a handler class (also per the above example). Javascript inside templates can be really tricky to debug since none of the line numbers correspond and you have both server-side (Smarty) munging and client-side (Javascript) execution happening in the same place.

I think the global object might be a necessary evil in order to easily present the data to Lens, because that’s third-party code and uses a different structure than our Javascript does, but you might consider using the existing $.pkp.cons object rather than creating a fresh one.

Off the top of my head, you might have one or two places where escaping is needed or should be moved closer to the area it’s needed. This is tricky to get right, and keeping the escaping nearest the place where it has to be applied (e.g. keeping the json_encode nearest the handover from template-land to Javascript) makes it easier to maintain and audit code later and prevent things like XSS attacks from creeping in.

Alec Smecher
Public Knowledge Project Team

1 Like