`
+
+2. Above the closing `` tag, add
+
+ ```html
+
+ ```
+
+3. In your scripts, include your custom values:
+ * the class name where your widget will appear for the `container-class` key and
+ * the doi for the paper you are interested in as the `article-doi` key
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/docs/widget.md b/docs/widget.md
new file mode 100644
index 0000000..37ebcd5
--- /dev/null
+++ b/docs/widget.md
@@ -0,0 +1,45 @@
+# widget.js Documentation
+This shows what the Paper Badger Widget can do and how to use it.
+
+## Usage
+1. To use the widget on your own site, include a `
` with your custom class in your view file, for example:
+ `
`
+
+2. Above the closing `` tag, add
+ ```html
+
+ ```
+
+3. In the load method, include your custom values:
+ * the element class where your widget will appear for the `containerClass` key and
+ * either the doi for the paper you are interested in as the `DOI` key or the ORCID for the author you are interesed in as the `ORCID` key
+
+## Required configuration options
+ * the `containerClass` key: contains the class of the element which will contain the Paper Badger widget
+ * either the `DOI` or the `ORCID` key: defines which information the widget will display
+
+## Optional configuration options
+ * the `ORCIDWidgetType` key (only in combination with the `ORCID` key): set the key to the value `default` to show names below the badges, set it to `DOI` to show DOIs
+ * the `loaderText` key: changes the default text shown while the Paper Badger widget is loading
+ * the `removeClass` key: the widget will remove this class from all elements once it has loaded, if this is a non-empty string
+ * the `clickCallback` key: a method that gets called when a link under a badge gets clicked. The method is called with an object containing either the DOI or ORCID of the link and the badge taxonomy:
+
+ ```
+ {
+ doi: '10.1186/2047-217X-3-18', // either DOI
+ orcid: '0000-0001-5207-5061', // or ORCID
+ taxonomy: 'data_curation'
+ }
+ ```
diff --git a/package.json b/package.json
index 2edbdcf..3fb05fc 100644
--- a/package.json
+++ b/package.json
@@ -9,10 +9,10 @@
"watch:js": "npm run build:js -- --watch",
"clean": "rm -r public/js/*",
"server": "node src/index.js",
- "jscs": "jscs -c node_modules/mofo-style/linters/.jscsrc src test webpack.config.js",
- "jshint": "jshint -c .jshintrc src webpack.config.js",
+ "jscs": "jscs -c node_modules/mofo-style/linters/.jscsrc src test webpack.config.js public/widgets/widget.js",
+ "jshint": "jshint -c .jshintrc src webpack.config.js public/widgets/widget.js",
"jshint:test": "jshint -c test/.jshintrc test",
- "jsbeautify": "js-beautify --config node_modules/mofo-style/linters/.jsbeautifyrc src/*.js test/*.js webpack.config.js -r -n",
+ "jsbeautify": "js-beautify --config node_modules/mofo-style/linters/.jsbeautifyrc src/*.js test/*.js webpack.config.js public/widgets/widget.js -r -n",
"lint": "npm run jsbeautify && npm run jshint && npm run jshint:test && npm run jscs",
"build:production": "npm run build:js -- --optimize-minimize --optimize-dedupe",
"start:production": "npm-run-all build:production server",
diff --git a/public/widgets/demos/doi-widget.html b/public/widgets/demos/doi-widget.html
new file mode 100644
index 0000000..e8d6967
--- /dev/null
+++ b/public/widgets/demos/doi-widget.html
@@ -0,0 +1,28 @@
+
+
+
+
+
Paper view snippet example | Paper Badger
+
+
+
+
+
+
This text is only shown when the API returns badges.
+
+
+
+
\ No newline at end of file
diff --git a/public/widgets/demos/orcid-widget-with-doi-shown.html b/public/widgets/demos/orcid-widget-with-doi-shown.html
new file mode 100644
index 0000000..9a14c96
--- /dev/null
+++ b/public/widgets/demos/orcid-widget-with-doi-shown.html
@@ -0,0 +1,26 @@
+
+
+
+
+
Paper view snippet example | Paper Badger
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/widgets/demos/orcid-widget-with-name-shown.html b/public/widgets/demos/orcid-widget-with-name-shown.html
new file mode 100644
index 0000000..29be50a
--- /dev/null
+++ b/public/widgets/demos/orcid-widget-with-name-shown.html
@@ -0,0 +1,25 @@
+
+
+
+
+
Paper view snippet example | Paper Badger
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/widgets/widget.js b/public/widgets/widget.js
new file mode 100644
index 0000000..8a5cc68
--- /dev/null
+++ b/public/widgets/widget.js
@@ -0,0 +1,355 @@
+/* exported PaperBadgerWidget */
+/* global ActiveXObject: false */
+/**
+ * PaperBadger widget
+ * Displays all badges for a DOI or ORCID.
+ *
+ * @param {Object} settings
+ * @param {string=} settings.DOI
+ * @param {string=} settings.ORCID
+ * @param {string} settings.containerClass
+ * @param {string=} settings.ORCIDWidgetType
+ * @param {string=} settings.loaderText
+ * @param {string=} settings.removeClass
+ * @param {Function=} settings.clickCallback
+ * @constructor
+ */
+var PaperBadgerWidget = function (settings) {
+ /**
+ * Widget container element
+ * @type {Element}
+ */
+ var containerElement;
+
+ /**
+ * Determines whether the ORCID widget shows the
+ * author's name or DOIs
+ * @type {string}
+ */
+ var ORCIDWidgetType = 'default';
+
+ /**
+ * String shown in the loading animation
+ * @type {string}
+ */
+ var loaderText = 'loading widget';
+
+ /**
+ * Element for the loading animation
+ * @type {Element}
+ */
+ var loaderElement;
+
+ /**
+ * Contains the interval id for the animation loop
+ * @type {Number}
+ */
+ var loaderInterval;
+
+ /**
+ * Checks the settings given to the function and starts
+ * the widget creation.
+ */
+ var construct = function () {
+ // fix for #135, all but the first forward slash of a DOI
+ // should be encoded as %2F
+ if (settings.hasOwnProperty('DOI')) {
+ var tmp = settings.DOI.split('/');
+ settings.DOI = tmp[0] + '/' + tmp.slice(1).join('%2F');
+ }
+
+ containerElement = document.getElementsByClassName(settings.containerClass)[0];
+
+ // Changes the ORCID widget type to DOI if the user requests it.
+ if (settings.hasOwnProperty('ORCIDWidgetType') && settings.ORCIDWidgetType === 'DOI') {
+ ORCIDWidgetType = 'DOI';
+ }
+
+ if (settings.hasOwnProperty('loaderText')) {
+ loaderText = settings.loaderText;
+ }
+
+ // we need a container element and either a DOI or an ORCID
+ // proceed if these are available, throw an error if not
+ if (containerElement && (settings.hasOwnProperty('DOI') || settings.hasOwnProperty('ORCID'))) {
+ insertCSS();
+ startLoader();
+ loadWidgetContent();
+ } else {
+ throw 'The settings object is incomplete. You need to supply an element id and either a DOI or an ORCID.';
+ }
+ };
+
+ /**
+ * Injects a style tag into the header containing the necessary
+ * styles for the widget.
+ */
+ var insertCSS = function () {
+ var css = '.paper-badge {float: left; width: 10em; height: 20em; overflow: hidden; ' +
+ 'border-top: 1px solid #ccc; height 15em; padding: 2%; margin-right: 1%; margin-top: 2%}' +
+ '.paper-badge a {width: 100%; display: inline-block; font-size: 88%; line-height: 1.2; ' +
+ 'color: #333; padding: 0.4em; cursor: pointer; text-decoration: none} .paper-badge ' +
+ 'a.active {color: #fff; background: #7ab441; text-decoration: none} .paper-badge img ' +
+ '{max-width: 8em; margin-left: 10%; margin-bottom: 1%} .paper-badges-hidden{display: none}';
+
+ var head = document.head || document.getElementsByTagName('head')[0];
+ var style = document.createElement('style');
+ style.type = 'text/css';
+ if (style.styleSheet) {
+ style.styleSheet.cssText = css;
+ } else {
+ style.appendChild(document.createTextNode(css));
+ }
+
+ head.appendChild(style);
+ };
+
+ /**
+ * Inserts the loader element into the container element
+ * and starts an animation loop.
+ */
+ var startLoader = function () {
+ loaderElement = document.createElement('div');
+ loaderElement.className = 'paperbadger-loader';
+ loaderElement.setAttribute('data-step', '4');
+ containerElement.appendChild(loaderElement);
+ loaderMethod();
+
+ loaderInterval = setInterval(loaderMethod, 750);
+ };
+
+ /**
+ * Animation loop for the loader text. Adds / removes
+ * dots from the loader text.
+ */
+ var loaderMethod = function () {
+ var step = loaderElement.getAttribute('data-step');
+ var text = loaderText;
+
+ if (step === '4') {
+ step = 1;
+ } else if (step === '1') {
+ step = 2;
+ text += '.';
+ } else if (step === '2') {
+ step = 3;
+ text += '..';
+ } else if (step === '3') {
+ step = 4;
+ text += '...';
+ }
+
+ loaderElement.innerHTML = text;
+ loaderElement.setAttribute('data-step', step);
+ };
+
+ /**
+ * Stops the loader animation loop.
+ */
+ var stopLoader = function () {
+ clearInterval(loaderInterval);
+ };
+
+ /**
+ * Loads the widget content from the Badges API.
+ */
+ var loadWidgetContent = function () {
+ var url = getEndpoint();
+ var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
+
+ xmlhttp.onreadystatechange = function () {
+ if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
+ stopLoader();
+ processAjaxResponse(xmlhttp.responseText);
+ }
+ };
+
+ xmlhttp.open('GET', url, true);
+ xmlhttp.send();
+ };
+
+ /**
+ * Generates the endpoint url depending on the
+ * widget settings.
+ *
+ * @returns {string}
+ */
+ var getEndpoint = function () {
+ var url = 'https://badges.mozillascience.org/';
+
+ if (settings.DOI) {
+ url += 'papers/' + settings.DOI;
+ } else if (settings.ORCID) {
+ url += 'users/' + settings.ORCID;
+ } else {
+ throw 'You need to supply either a DOI or an ORCID.';
+ }
+
+ url += '/badges';
+
+ return url;
+ };
+
+ /**
+ * Processes the data from the Badges API so it
+ * can be rendered in the next step.
+ *
+ * @param {string} json
+ */
+ var processAjaxResponse = function (json) {
+ var badgesJson = JSON.parse(json);
+ var badges = {};
+ var isDOI = (settings.hasOwnProperty('DOI') && settings.DOI.length);
+
+ for (var i = 0; i < badgesJson.length; i++) {
+ var badgeId = badgesJson[i].badge.slug;
+ if (!badges.hasOwnProperty(badgeId)) {
+ badges[badgeId] = {
+ name: badgesJson[i].badge.name,
+ consumerDescription: badgesJson[i].badge.consumerDescription,
+ imageUrl: badgesJson[i].badge.imageUrl,
+ links: []
+ };
+ }
+
+ // depending whether we have a DOI widget, an ORCID default widget
+ // ( = displays names) or an ORCID display a list
+ // of either authors or articles for a badge
+ if (isDOI || ORCIDWidgetType === 'default') {
+ badges[badgeId].links.push({
+ id: badgesJson[i].orcid,
+ type: 'ORCID',
+ taxonomy: badgeId,
+ text: badgesJson[i].authorName,
+ url: 'https://orcid.org/' + badgesJson[i].orcid
+ });
+ } else {
+ var localDOI = badgesJson[i].evidenceUrl.split('doi.org/')[1];
+
+ badges[badgeId].links.push({
+ id: localDOI,
+ type: 'DOI',
+ taxonomy: badgeId,
+ text: localDOI,
+ url: badgesJson[i].evidenceUrl.replace('http:', 'https:')
+ });
+ }
+ }
+
+ renderBadges(badges);
+ };
+
+ /**
+ * Generates and displays the HTML code for the received
+ * badge data.
+ *
+ * @param {Object} badges
+ */
+ var renderBadges = function (badges) {
+ var i = 0;
+ var html = '';
+ var numBadges = 0;
+
+ for (var key in badges) {
+ if (badges.hasOwnProperty(key)) {
+ numBadges++;
+
+ html += '
';
+ }
+ }
+
+ containerElement.innerHTML = html;
+
+ // if there were any badges and if the user supplied
+ // removeClass in the settings, remove the class from
+ // all elements on the page
+ if (numBadges && settings.hasOwnProperty('removeClass') && settings.removeClass.length) {
+ var elements = document.getElementsByClassName(settings.removeClass);
+
+ for (i = 0; i < elements.length; i++) {
+ var classes = elements[i].className.split(' ');
+ for (var j = 0; j < classes.length; j++) {
+ if (classes[j] === settings.removeClass) {
+ classes.splice(j, 1);
+ }
+ }
+ elements[i].className = classes.join(' ');
+ }
+ }
+
+ // add mouseover and clickCallbacks for all links
+ var links = document.getElementsByClassName('paper-badger-link');
+ for (i = 0; i < links.length - 1; i++) {
+ links[i].addEventListener('mouseover', mouseOverMethod);
+ links[i].addEventListener('click', clickCallbackMethod);
+ }
+ };
+
+ /**
+ * Marks all occurrences of an author on mouse over
+ * by adding a .active CSS class to the link element.
+ */
+ var mouseOverMethod = function () {
+ var id = this.getAttribute('data-id');
+ var links = document.getElementsByClassName('paper-badger-link');
+
+ for (var i = 0; i < links.length; i++) {
+ var j = 0;
+ var classes = links[i].className.split(' ');
+
+ if (links[i].getAttribute('data-id') === id) {
+ var found = false;
+ for (j = 0; j < classes.length - 1; j++) {
+ if (classes[j] === 'active') {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ classes.push('active');
+ }
+ } else {
+ for (j = classes.length; j > 0; j--) {
+ if (classes[j] === 'active') {
+ classes.splice(j, 1);
+ }
+ }
+ }
+
+ links[i].className = classes.join(' ');
+ }
+ };
+
+ /**
+ * Calls the clickCallback method if the user supplied one
+ */
+ var clickCallbackMethod = function () {
+ if (settings.hasOwnProperty('clickCallback') && settings.clickCallback) {
+ var data = {
+ taxonomy: this.getAttribute('data-taxonomy')
+ };
+
+ if (this.getAttribute('data-type') === 'DOI') {
+ data.doi = this.getAttribute('data-id');
+ } else if (this.getAttribute('data-type') === 'ORCID') {
+ data.orcid = this.getAttribute('data-id');
+ }
+
+ settings.clickCallback(data);
+ }
+ };
+
+ construct();
+};