• Stars
    star
    363
  • Rank 117,374 (Top 3 %)
  • Language
    JavaScript
  • License
    Other
  • Created over 11 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A novel way of seeing content

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.

// 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
  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...

echo "lts/dubnium" > .nvmrc
nvm install
nvm use
echo "2.7.17" > .python-version
pyenv install
pvenv local
  1. Fetch dependencies
npm install
  1. Run the server
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

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

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

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

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:[email protected]", 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

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

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

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

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

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

var panels = Lens.getDefaultPanels();

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

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

Bundling

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

$ gulp

You can find your bundle in the dist folder.

$ cd dist
$ python -m SimpleHTTPServer

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

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)

More Repositories

1

sciencebeam-parser

A set of tools to allow PDF to XML conversion, utilising Apache Beam and other tools. The aim of this project is to bring multiple tools together to generate a full XML document.
Python
294
star
2

elife-xpub

eLife is an open-access journal and technology provider that publishes promising research in the life and biomedical sciences. This is their implementation of a submission and peer review system based on Coko PubSweet and xPub.
JavaScript
29
star
3

datacapsule-crossref

Retrieve and extract citations from Crossref data
Jupyter Notebook
28
star
4

sciencebeam-gym

ScienceBeam Gym
Python
25
star
5

elife-article-xml

Full XML of all eLife articles including each revision.
24
star
6

elife-bot

tools for creating an automatic publishing workflow.
Python
19
star
7

journal

eLife is an open-access journal that publishes promising research in the life and biomedical sciences
PHP
16
star
8

elife-tools

Tools for using article data in Python
Python
14
star
9

elife-continuum-documentation

ppp project related files and prototypes
HTML
13
star
10

lens-browser

Lens Article Browser
JavaScript
12
star
11

lens-converter

A client-side NLM to Lens converter. Based on Substance.Converter.
JavaScript
11
star
12

elife-articles

xml of elife articles
10
star
13

refract

Convert NLM XML files into the Lens JSON
JavaScript
9
star
14

builder

Python
8
star
15

elife-jenkins-workflow-libs

Common steps used in eLife's Jenkins Pipelines
Groovy
8
star
16

citation-context

Jupyter Notebook
7
star
17

lens-indexer

Lens Indexer based on ElasticSearch.
JavaScript
7
star
18

rds-example

Stand-alone example of a reproducible document stack article
JavaScript
6
star
19

api-raml

RAML for the eLife Sciences API
RAML
6
star
20

pattern-library

Pattern library driving https://elifesciences.org, the eLife journal.
JavaScript
6
star
21

reference-schematron

5
star
22

sciencebeam-trainer-delft

Wrapper around https://github.com/kermitt2/delft
Python
5
star
23

proofreader-php

proofreader-php is a tool for enforcing opinionated coding standards and conventions through static analysis of the code.
PHP
5
star
24

sciencebeam-airflow

Airflow pipeline for ScienceBeam related training and evaluation
Python
5
star
25

jats-scraper

standalone article xml scraper for the pppp project
Python
4
star
26

elife-crossref-xml-generation

Crossref deposit of journal articles
Python
4
star
27

lax

Python
4
star
28

lens-reader

The Lens Reader as a module, for custom app integration
JavaScript
4
star
29

basex-validator-docker

XML Validation service built on BaseX for validating XML against elife's schematron files
XSLT
4
star
30

lens-elife

eLife integrations of Lens with custom extensions as well as official bundle
JavaScript
4
star
31

publisher-xml-fragment-examples

4
star
32

isolated-drupal-behat-extension

Extension for Behat that tests Drupal sites in isolation.
PHP
4
star
33

lens-outline

Visually outlines Substance documents.
JavaScript
4
star
34

search

PHP
3
star
35

journal-cms

PHP
3
star
36

jats-generator

JATS XML generator
Python
3
star
37

jats-xml-to-pdf

Shell
3
star
38

peerscout

PeerScout® is a web application and machine learning trained API for suggesting peer reviewers from an existing pool, based on attributes of the papers they have reviewed and written
Python
3
star
39

bot-lax-adaptor

Python
3
star
40

XML-mapping

Mapping the XML to new Continuum requirements and build of a new Kitchen sink
3
star
41

eLife-JATS-schematron

Schematron for all JATS eLife content
XSLT
3
star
42

elife-pdfs

pdf versions of elife articles
3
star
43

threadbare

A partial replacement for eLife's usage of Fabric 1.x and Paramiko.
Python
3
star
44

cermine-docker

Shell
3
star
45

data-science-peertax

Data Science project looking into the Peer Review Taxonomy
Jupyter Notebook
3
star
46

elife-flux-cluster

Definition of eLife's k8s cluster and deployments to it. Automatically applied via Flux.
Shell
3
star
47

medium

eLife Medium articles API
PHP
2
star
48

api-dummy

Dummy implementation of the eLife Sciences API
PHP
2
star
49

lens-sandbox

Lens Development Environment
JavaScript
2
star
50

elife-article-scheduler

manage scheduling future publications for eLife Continuum
Python
2
star
51

bus-sdk-php

PHP SDK for the eLife Sciences bus [in development]
PHP
2
star
52

elife-metrics

Python
2
star
53

schematron-wiki

This contains the markdown from gitbook for schematron.
XQuery
2
star
54

lens-starter

Minimal Lens integration, use as a starting point for development
JavaScript
2
star
55

elife-api

Python
2
star
56

data-hub-ejp-xml-pipeline

Data pipeline for loading eJP Xml files from S3 bucket into Bigquery
Python
2
star
57

data-science-dags

Python
2
star
58

sciencebeam-utils

ScienceBeam Utils
Python
2
star
59

peerscout-dags

Python
2
star
60

citation-sentiment-analysis

Jupyter Notebook
2
star
61

elife-data-hub-utils

Utility functions related to elife-data-hub
Python
2
star
62

data-hub-airflow-image

create custom airflow image used for running data-hub pipeline
Makefile
2
star
63

enhanced-preprints-client

Enhanced Preprints client application
TypeScript
2
star
64

data-hub-core-airflow-dags

Python
2
star
65

builder-configuration

Contains non-sensitive Salt formulas configuration
SaltStack
2
star
66

patterns-php

PHP implementation of the eLife patterns
PHP
2
star
67

data-pipeline-sql-prototype

A central place for resources relating to the eLife Data Pipeline tools
Python
2
star
68

bigquery-views-manager

BigQuery Views Manager
Python
2
star
69

packer-test

files for testing packer
Ruby
2
star
70

elife-drupal-cookbook

elife version of drupal cookbook
PHP
2
star
71

populate-elife-api

scripts for getting elife xml, parsing them, and populating our REST api
Python
2
star
72

developer-resources

Are you a developer or hacker interested in using eLife's open-source resources? This page is for you! If you do build something using our code, we'd love to hear at [email protected] (we may be able to help you grow your project).
2
star
73

elife-alfred-formula

SaltStack
1
star
74

JATs-xml

eLife upgrade to JATS xml
1
star
75

api-gateway-formula

SaltStack
1
star
76

elife-dashboard

publishing dashboard for eLife Continuum
JavaScript
1
star
77

enhanced-preprints-import

Enhanced Preprints import system
TypeScript
1
star
78

elife-kickstart

Build script to make it easier to start building a distribution for a new Drupal project.
Shell
1
star
79

sciencebeam-editor

JavaScript
1
star
80

eif-article-json

Shell
1
star
81

elife-data-hub-charts

Smarty
1
star
82

api-client-php

PHP client for the eLife Sciences API
PHP
1
star
83

journal-cms-formula

SaltStack
1
star
84

citerank

Calculates PageRank over citation data
Python
1
star
85

builder-base-formula

SaltStack
1
star
86

lens-library

Library of eLife Articles, used as a landing page at lens.elifesciences.org
JavaScript
1
star
87

elife-metrics-formula

SaltStack
1
star
88

elife-flux-test

Declares the deploys to kubernetes-aws--flux-test cluster using fluxcd
Shell
1
star
89

lens-s3

HTML
1
star
90

elife-article-xml-continuumtest

Testing repository. Contents may be DELETED at any time.
1
star
91

data-hub-api

Data Hup APIs
Python
1
star
92

elife-utility-scripts

a collection of utility scripts used at eLife
JavaScript
1
star
93

api-sdk-php

PHP SDK for the eLife Sciences API
PHP
1
star
94

elife-crossref-feed

code to support uploading info to crossref on PAW articles
1
star
95

pubpub-css

To enable version control of the CSS in PubPub's static page system
CSS
1
star
96

elife-website

PHP
1
star
97

sciencebeam-trainer-grobid

ScienceBeam Trainer for GROBID
Python
1
star
98

hypothesis-dummy

Minimal dummy to stand in for Hypothes.is inside eLife's testing infrastructure
PHP
1
star
99

bioprotocol-service

Python
1
star
100

master-server-formula

SaltStack
1
star