https://github.com/elifesciences/lens

A novel way of viewing eLife articles.

https://github.com/elifesciences/lens

Science Score: 13.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
  • .zenodo.json file
  • DOI references
    Found 1 DOI reference(s) in README
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (13.8%) to scientific vocabulary
Last synced: 11 months ago · JSON representation

Repository

A novel way of viewing eLife articles.

Basic Info
  • Host: GitHub
  • Owner: elifesciences
  • License: other
  • Language: JavaScript
  • Default Branch: develop
  • Homepage: http://lens.elifesciences.org
  • Size: 4.91 MB
Statistics
  • Stars: 378
  • Watchers: 34
  • Forks: 74
  • Open Issues: 42
  • Releases: 0
Created about 13 years ago · Last pushed over 4 years ago
Metadata Files
Readme Changelog License

README.md

Lens

Lens provides a novel way of looking at content on the web. It is designed to make life easier for researchers, reviewers, authors and readers.

Using Lens

Lens is a stand-alone web component that can be embedded into any web page. Just take the contents from the latest distribution, then adjust the document_url parameter in index.html.

```js // Endpoint must have CORS enabled, or file is served from the same domain as the app var documentURL = "https://s3.amazonaws.com/elife-cdn/elife-articles/00778/elife00778.xml";

var app = new Lens({ document_url: documentURL }); ```

Lens can display any NLM XML document or, alternatively, the Lens-native JSON representation. Lens is pure client-side Javascript, so anyone (even authors) can host their own documents on a regular webspace.

Make your own Lens

Lens is meant to be extended and customized. The American Mathematical Society developed a math extension for the Lens Reader to display JATS files with Math content, i.e. environments and formulas. See the official AMS Lens repo for a complete integration example.

However, now let's look into developing our own extensions.

Prerequisites

For Lens development, you need to have Node.js >=10.x installed.

You need to repeat that install step whenever you updated the screwdriver repo.

Setup

  1. Clone the lens-starter repository

bash git clone https://github.com/elifesciences/lens-starter.git cd lens-starter

  1. Configure System

As stated above, you'll need version 10.x of Node installed, and you'll also need version 2.7.x of Python available. You can use nvm to manage which version of node to use on a per-project basis, and PyEnv to do the same for Python. With both of these tools setup, you can...

bash echo "lts/dubnium" > .nvmrc nvm install nvm use echo "2.7.17" > .python-version pyenv install pvenv local

  1. Fetch dependencies

bash npm install

  1. Run the server

bash npm start

Then navigate to http://127.0.0.1:4001/ in your web browser.

Converter

Lens can natively read the JATS (formerly NLM) format, thanks to its built-in converter. Conversion is done on the client side using the browser-native DOM Parser.

You can find the implementation of Lens Converter here. Lens Converter is meant to be customized, so publishers can develop a their own flavor easily.

Each converter must have a method test that takes the XML document as well as the document url. The method is there to tell if the converter can handle the content or not. In the case of eLife we check for the publisher-name element in the XML.

See: lens/converter/elife_converter.js

js ElifeConverter.Prototype = function() { ... this.test = function(xmlDoc, documentUrl) { var publisherName = xmlDoc.querySelector("publisher-name").textContent; return publisherName === "eLife Sciences Publications, Ltd"; }; ... };

A customized converter can override any method of the original LensConverter. However, we have designated some hooks that are intended to be customized. Watch for methods starting with enhance. For eLife we needed to resolve supplement urls, so we implemented an enhanceSupplement method, to resolve the supplement.url according to a fixed url scheme that eLife uses.

See: lens/converter/elife_converter.js

js ElifeConverter.Prototype = function() { ... this.enhanceSupplement = function(state, node) { var baseURL = this.getBaseURL(state); if (baseURL) { return [baseURL, node.url].join(''); } else { node.url = [ "https://cdn.elifesciences.org/elife-articles/", state.doc.id, "/suppl/", node.url ].join(''); } }; ... };

You can configure a chain of converters if you need to support different journals at a time for a single Lens instance.

See src/my-lens.js

js LensApp.Prototype = function() { this.getConverters = function(converterOptions) { return [ new ElifeConverter(converterOptions), new PLOSConverter(converterOptions), new LensConverter(converterOptions) ] }; ... };

The Converter.test method will be called on each instance with the XML document to be processed. The one that returns true first will be used. You can change the order to prioritize converters over others.

Custom Nodes

You may want to customize how information is displayed in Lens. Here's how it works.

Define node model and view

We can either define a completely new node or override an existing implementation.

The following example from the starter repo overrides the Cover node and adds a feedback link to the top.

See lens-starter/src/nodes/cover/cover_view.js

```js CustomCoverView.Prototype = function() { this.render = function() { CoverView.prototype.render.call(this);

var refUrl = encodeURIComponent(window.location.href);

// Add feeback info
var introEl = $$('.intro.container', {
  children: [
    $$('.intro-text', {
      html: '<i class="fa fa-info"></i>&nbsp;&nbsp;<b>Lens</b> provides a novel way of viewing research'
    }),
    $$('a.send-feedback', {href: "mailto:feeback@example.com", text: "Send feedback", target: "_blank" })
  ]
});

// Prepend
this.content.insertBefore(introEl, this.content.firstChild);

return this;

} }; ```

In this example only the view code is modified while the original model definition is being reused.

See lens-starter/src/nodes/cover/index.js

```js var LensNodes = require("lens/article/nodes"); var CoverModel = LensNodes["cover"].Model;

module.exports = { Model: CoverModel, View: require('./cover_view') }; ```

In order to activate in that patched node, your custom converter has to instantiate a custom Lens Article instance.

See lens-starter/src/custom_converter.js

```js var CustomNodeTypes = require("./nodes");

CustomConverter.Prototype = function() { ... // Override document factory so we can create a customized Lens article, // including overridden node types this.createDocument = function() { var doc = new LensArticle({ nodeTypes: CustomNodeTypes }); return doc; }; ... ```

Panels

Lens can easily be extended with a customized panel. It can be used to show additional information relevant to the displayed article. A few examples of what you could do:

  • Pull in tweets that talk about the current article
  • Pull in metrics (click count, number of articles citing that article etc.)
  • Retrieve related articles dynamically (e.g. important ones that reference the existing one)

For demonstration we will look at the implementation of a simple Altmetrics panel. It will pull data asynchronously from the Altmetrics API (https://api.altmetric.com/v1/doi/10.7554/eLife.00005) and render the information in Lens.

Panel Definition

This is the main entry point for a panel.

See: lens-starter/src/panels/altmetrics/index.js

```js var panel = new Panel({ name: "altmetrics", type: 'resource', title: 'Altmetrics', icon: 'fa-bar-chart', });

panel.createController = function(doc) { return new AltmetricsController(doc, this.config); }; ```

Panel Controller

Our custom controller provides a getAltmetrics method, that we will use in the view to fetch data from altmetrics.com asynchronously. Using the Substance Document API we retrieve the DOI, which is stored on the publication_info node.

See: lens-starter/src/panels/altmetrics/altmetrics_controller.js

```js var AltmetricsController = function(document, config) { PanelController.call(this, document, config); };

AltmetricsController.Prototype = function() { ... this.getAltmetrics = function(cb) { var doi = this.document.get('publication_info').doi;

$.ajax({
  url: "https://api.altmetric.com/v1/doi/"+doi,
  dataType: "json",
}).done(function(res) {
  cb(null, res);
}).error(function(err) {
  cb(err);
});

}; ... }; ```

Panel View

The Panel View is where you define, what should be rendered in your custom panel. Your implementation needs to inherit from Lens.PanelView and define a render method. The implementation of the altmetrics panel is pretty simple. We will show the panel (PanelView.showToggle) as soon as data from altmetric.com has arrived.

See: lens-starter/src/panels/altmetrics/index.js

```js var AltmetricsView = function(panelCtrl, config) { PanelView.call(this, panelCtrl, config); this.$el.addClass('altmetrics-panel'); // Hide toggle on contruction, it will be displayed once data has arrived this.hideToggle(); };

AltmetricsView.Prototype = function() { ... this.render = function() { var self = this; this.el.innerHTML = '';

this.controller.getAltmetrics(function(err, altmetrics) {
  if (!err) {
    self.renderAltmetrics(altmetrics);  
  } else {
    console.error("Could not retrieve altmetrics data:", err);
  }
});
return this;

}; ... }; ```

Activate Panel

Panels are enabled in the projects app.js file by manipulating the panels array.

See: lens-starter/src/app.js

js var panels = Lens.getDefaultPanels();

This code adds the altmetrics panel to the next to last position (before the info panel).

js var altmetricsPanel = require('./panels/altmetrics'); panels.splice(-1, 0, altmetricsPanel);

Bundling

Lens uses gulp and browserify for bundling. Just run the gulp command.

bash $ gulp

You can find your bundle in the dist folder.

bash $ cd dist $ python -m SimpleHTTPServer

To open one of the bundled samples you need open the following URL in your browser

bash http://127.0.0.1:8000/

Adjust the 'url' parameter to open a different document.

A note on mobile

Mobile support has been removed with Lens 2.0 to reduce technical debt and iterate more quickly on features. Eventually the Lens team will come up with a dedicated reader for mobile. We want to solve it right, and eventually also ship native versions for iOS and Android.

Credits

Lens was developed in collaboration between UC Berkeley graduate student Ivan Grubisic and eLife. The team of Substance is helping with the technical execution.

Substantial contributions were made by HighWire, which launched Lens for a number of science journals in fall 2014 (The Journal of Biological Chemistry, The Plant Cell, Journal of Lipid Research, mBio®, and more). The American Mathematical Society (AMS) made Lens ready for advanced rendering of math articles.

Thanks go to the following people, who made Lens possible:

  • Ivan Grubisic (concept, dev)
  • Ian Mulvany (leadership)
  • Oliver Buchtala (dev)
  • Michael Aufreiter (dev)
  • Graham Nott (infrastructure)
  • Melissa Harrison (QA)
  • Rebecca Close (converter)
  • Felix Breuer (math)
  • David Jones (math)
  • Peter Krautzberger (math)
  • Samo Korošec (design)
  • Ian Hamilton (design)
  • John Sack (guidance)
  • Greg Schwartz (content variation)

Owner

  • Name: eLife Sciences Publications Ltd
  • Login: elifesciences
  • Kind: organization
  • Location: Cambridge, UK

eLife is a not for profit inspired by research funders and led by scientists, to help accelerate discovery by operating a platform for research communication

GitHub Events

Total
  • Watch event: 2
  • Fork event: 1
Last Year
  • Watch event: 2
  • Fork event: 1

Committers

Last synced: about 1 year ago

All Time
  • Total Commits: 586
  • Total Committers: 17
  • Avg Commits per committer: 34.471
  • Development Distribution Score (DDS): 0.377
Past Year
  • Commits: 0
  • Committers: 0
  • Avg Commits per committer: 0.0
  • Development Distribution Score (DDS): 0.0
Top Committers
Name Email Commits
Michael Aufreiter m****l@s****o 365
Oliver Buchtala o****a@g****m 99
Michael Aufreiter ma@z****t 25
Ivan Grubisic i****b@g****m 22
Oliver Buchtala o****a@g****m 21
Graham Nott g****t@s****a 20
Peter Krautzberger p****r@g****m 7
Rebecca Close r****a@l****m 6
withanage d****e@g****m 4
Joel Summerfield 5****e 4
Luke Skibinski l****i@e****g 4
Ian Mulvany i****n@m****t 3
David Moreno Cortina d****a@g****m 2
Chris Wilkinson c****n@e****g 1
Giorgio Sironi g****i@e****g 1
Niru Maheswaranathan n****m 1
Victor Saiz v****e@g****m 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: about 1 year ago

All Time
  • Total issues: 61
  • Total pull requests: 40
  • Average time to close issues: over 1 year
  • Average time to close pull requests: about 1 month
  • Total issue authors: 31
  • Total pull request authors: 11
  • Average comments per issue: 2.03
  • Average comments per pull request: 1.05
  • Merged pull requests: 32
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 1
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 1
  • Pull request authors: 0
  • Average comments per issue: 0.0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • pkra (16)
  • gnott (8)
  • juanCure (2)
  • willgdjones (2)
  • sianroderick (2)
  • CAYdenberg (2)
  • JGilbert-eLife (2)
  • withanage (2)
  • Melissa37 (2)
  • blahah (2)
  • ppKrauss (1)
  • michael (1)
  • anupsankar (1)
  • abigailv (1)
  • ficolo (1)
Pull Request Authors
  • gnott (12)
  • pkra (10)
  • michael (7)
  • obuchtala (3)
  • lsh-0 (2)
  • giorgiosironi (1)
  • DavidMorenoCortina (1)
  • CAYdenberg (1)
  • orthographic-pedant (1)
  • NuclearRedeye (1)
  • thewilkybarkid (1)
Top Labels
Issue Labels
bug (2)
Pull Request Labels
dont-merge (1)

Packages

  • Total packages: 3
  • Total downloads:
    • npm 28 last-month
  • Total dependent packages: 3
    (may contain duplicates)
  • Total dependent repositories: 3
    (may contain duplicates)
  • Total versions: 4
  • Total maintainers: 2
npmjs.org: elife-lens

A novel way of seeing content.

  • Versions: 2
  • Dependent Packages: 1
  • Dependent Repositories: 1
  • Downloads: 14 Last month
Rankings
Stargazers count: 3.3%
Forks count: 3.3%
Dependent repos count: 10.3%
Average: 17.4%
Dependent packages count: 21.0%
Downloads: 49.1%
Maintainers (1)
Last synced: 11 months ago
npmjs.org: ingenta-lens

A novel way of seeing content.

  • Versions: 1
  • Dependent Packages: 1
  • Dependent Repositories: 1
  • Downloads: 6 Last month
Rankings
Stargazers count: 3.3%
Forks count: 3.3%
Dependent repos count: 10.3%
Average: 17.4%
Dependent packages count: 21.0%
Downloads: 49.1%
Maintainers (1)
Last synced: 11 months ago
npmjs.org: @ingenta/lens

A novel way of seeing content.

  • Versions: 1
  • Dependent Packages: 1
  • Dependent Repositories: 1
  • Downloads: 8 Last month
Rankings
Stargazers count: 3.3%
Forks count: 3.3%
Dependent repos count: 10.3%
Average: 20.1%
Dependent packages count: 21.0%
Downloads: 62.6%
Maintainers (1)
Last synced: 11 months ago

Dependencies

package.json npm
  • underscore 1.12.1