├── oabutton
├── __init__.py
├── apps
│ ├── __init__.py
│ ├── metadata
│ │ ├── models.py
│ │ ├── __init__.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ └── tests.py
│ ├── web
│ │ ├── __init__.py
│ │ ├── templatetags
│ │ │ ├── __init__.py
│ │ │ └── oafilters.py
│ │ ├── models.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ ├── templates
│ │ │ └── web
│ │ │ │ ├── about.jade
│ │ │ │ ├── layout.jade
│ │ │ │ ├── start.jade
│ │ │ │ └── index.jade
│ │ └── tests.py
│ └── bookmarklet
│ │ ├── __init__.py
│ │ ├── auth_extra.py
│ │ ├── templatetags
│ │ ├── __init__.py
│ │ └── oafilters.py
│ │ ├── urls.py
│ │ ├── models.py
│ │ ├── templates
│ │ └── bookmarklet
│ │ │ ├── page3.html
│ │ │ ├── page1.html
│ │ │ ├── page2.html
│ │ │ ├── layout.html
│ │ │ └── bookmarklet.html
│ │ ├── tests.py
│ │ └── views.py
├── static
│ ├── public
│ │ ├── img
│ │ │ ├── bg.jpg
│ │ │ ├── pmc.png
│ │ │ ├── oalogo.png
│ │ │ ├── aperson.png
│ │ │ ├── favicon.ico
│ │ │ ├── noalogo.png
│ │ │ ├── scholar.png
│ │ │ ├── header_wide.png
│ │ │ ├── logo-medsin.jpg
│ │ │ ├── photo-david.jpg
│ │ │ ├── photo-joe.jpg
│ │ │ ├── oabutton_logo.eps
│ │ │ ├── oabutton_logo.png
│ │ │ ├── oabutton_badge.png
│ │ │ ├── oalogo_x_white.png
│ │ │ ├── webicon-facebook.png
│ │ │ ├── webicon-twitter.png
│ │ │ ├── header_needaccess.png
│ │ │ ├── iconmonstr-globe-3.png
│ │ │ ├── iconmonstr-video-5.png
│ │ │ ├── webicon-wordpress.png
│ │ │ ├── glyphicons-halflings.png
│ │ │ ├── iconmonstr-twitter-4.png
│ │ │ ├── oabutton-logo-100x150.png
│ │ │ ├── oabutton_logo_final200.png
│ │ │ ├── glyphicons-halflings-white.png
│ │ │ └── oabutton_logo_trans_bkgd.png
│ │ ├── font
│ │ │ ├── FontAwesome.otf
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ └── fontawesome-webfont.woff
│ │ ├── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ └── glyphicons-halflings-regular.woff
│ │ ├── less
│ │ │ ├── styles.less
│ │ │ ├── forms.less
│ │ │ └── app.less
│ │ ├── css
│ │ │ ├── MarkerCluster.css
│ │ │ ├── app.css
│ │ │ ├── MarkerCluster.Default.css
│ │ │ ├── leaflet.ie.css
│ │ │ ├── styles.css
│ │ │ ├── leaflet.css
│ │ │ └── bootstrap-theme.min.css
│ │ └── js
│ │ │ ├── compiler.sh
│ │ │ ├── success.js
│ │ │ ├── lib
│ │ │ ├── jquery.placeholder.js
│ │ │ ├── jquery.color-2.1.2.min.js
│ │ │ └── bootstrap-dialog.js
│ │ │ ├── add.js
│ │ │ └── index.js
│ └── test
│ │ ├── test.html
│ │ ├── resources
│ │ └── qunit.css
│ │ └── test.js
├── json_util.py
├── settings_local.py.example
├── urls.py
├── wsgi.py
├── settings.py
└── common
│ └── __init__.py
├── runtime.txt
├── Procfile
├── setup.cfg
├── .gitignore
├── .travis.yml
├── oabutton.sublime-project
├── Makefile
├── manage.py
├── requirements.txt
├── fabfile.py
├── LICENSE.md
├── Vagrantfile
├── deploy
└── gunicorn_start.sh
├── README.md
└── INSTRUCTIONS.md
/oabutton/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/oabutton/apps/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-2.7.4
2 |
--------------------------------------------------------------------------------
/oabutton/apps/metadata/models.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/oabutton/apps/web/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/oabutton/apps/metadata/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn oabutton.wsgi
2 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/auth_extra.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/oabutton/apps/web/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/oabutton/apps/web/models.py:
--------------------------------------------------------------------------------
1 | # Create your models here.
2 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | ignore = E501
3 | exclude = oab-env
4 |
--------------------------------------------------------------------------------
/oabutton/apps/web/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import patterns
2 |
3 | urlpatterns = patterns('')
4 |
--------------------------------------------------------------------------------
/oabutton/static/public/img/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/bg.jpg
--------------------------------------------------------------------------------
/oabutton/static/public/img/pmc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/pmc.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/oalogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/oalogo.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/aperson.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/aperson.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/favicon.ico
--------------------------------------------------------------------------------
/oabutton/static/public/img/noalogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/noalogo.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/scholar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/scholar.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/header_wide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/header_wide.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/logo-medsin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/logo-medsin.jpg
--------------------------------------------------------------------------------
/oabutton/static/public/img/photo-david.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/photo-david.jpg
--------------------------------------------------------------------------------
/oabutton/static/public/img/photo-joe.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/photo-joe.jpg
--------------------------------------------------------------------------------
/oabutton/static/public/font/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/font/FontAwesome.otf
--------------------------------------------------------------------------------
/oabutton/static/public/img/oabutton_logo.eps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/oabutton_logo.eps
--------------------------------------------------------------------------------
/oabutton/static/public/img/oabutton_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/oabutton_logo.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/oabutton_badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/oabutton_badge.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/oalogo_x_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/oalogo_x_white.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/webicon-facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/webicon-facebook.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/webicon-twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/webicon-twitter.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/header_needaccess.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/header_needaccess.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/iconmonstr-globe-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/iconmonstr-globe-3.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/iconmonstr-video-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/iconmonstr-video-5.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/webicon-wordpress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/webicon-wordpress.png
--------------------------------------------------------------------------------
/oabutton/static/public/font/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/font/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/oabutton/static/public/font/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/font/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/oabutton/static/public/font/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/font/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/oabutton/static/public/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/iconmonstr-twitter-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/iconmonstr-twitter-4.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/oabutton-logo-100x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/oabutton-logo-100x150.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/oabutton_logo_final200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/oabutton_logo_final200.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | data
2 | oab-env
3 | build
4 | *.pyc
5 | *.sqlite3
6 | .vagrant
7 | *.sw?
8 | venv
9 | settings_local.py
10 | *.sublime-workspace
11 | compiler.jar
12 |
--------------------------------------------------------------------------------
/oabutton/static/public/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/oabutton/static/public/img/oabutton_logo_trans_bkgd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/img/oabutton_logo_trans_bkgd.png
--------------------------------------------------------------------------------
/oabutton/static/public/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/oabutton/static/public/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/oabutton/static/public/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diracdeltas/OAButton/develop/oabutton/static/public/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "2.7"
4 | install: pip install -r requirements.txt --use-mirrors
5 | script:
6 | #- "flake8"
7 | - "python manage.py test web bookmarklet metadata"
8 | services:
9 | - mongodb
10 |
--------------------------------------------------------------------------------
/oabutton/apps/metadata/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import patterns, url
2 |
3 | from views import core_search
4 |
5 | urlpatterns = patterns('',
6 | url(r'^coresearch.json/(.*)$', core_search, name='core-search'))
7 |
--------------------------------------------------------------------------------
/oabutton/apps/web/templatetags/oafilters.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pyjade
4 |
5 |
6 | @pyjade.register_filter('label_with_classes')
7 | def label_with_classes(value, arg):
8 | return value.label_tag(attrs={'class': arg})
9 |
--------------------------------------------------------------------------------
/oabutton/static/public/less/styles.less:
--------------------------------------------------------------------------------
1 | /* Don't edit this CSS file. It's generated using lessc */
2 | @import "../css/MarkerCluster.css";
3 | @import "../css/MarkerCluster.Default.css";
4 |
5 | @import "app.less";
6 | @import "forms.less";
7 |
--------------------------------------------------------------------------------
/oabutton.sublime-project:
--------------------------------------------------------------------------------
1 | {
2 | "folders":
3 | [
4 | {
5 | "path": "."
6 | }
7 | ],
8 | "settings":
9 | {
10 | "tab_size": 4,
11 | "translate_tabs_to_spaces": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: test lessc
2 |
3 | all: build
4 |
5 | build: lessc
6 |
7 | lessc:
8 | lessc oabutton/static/public/less/styles.less oabutton/static/public/css/styles.css
9 |
10 |
11 | test:
12 | python manage.py test web bookmarklet metadata
13 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/templatetags/oafilters.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django import template
4 | register = template.Library()
5 |
6 |
7 | @register.filter(is_safe=True)
8 | def label_with_classes(value, arg):
9 | return value.label_tag(attrs={'class': arg})
10 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oabutton.settings")
7 |
8 | from django.core.management import execute_from_command_line
9 |
10 | execute_from_command_line(sys.argv)
11 |
--------------------------------------------------------------------------------
/oabutton/json_util.py:
--------------------------------------------------------------------------------
1 | from json import JSONEncoder
2 | import datetime
3 | from bson.objectid import ObjectId
4 |
5 |
6 | class MyEncoder(JSONEncoder):
7 |
8 | def default(self, obj):
9 | if isinstance(obj, ObjectId):
10 | return str(obj)
11 | if isinstance(obj, datetime.datetime):
12 | return obj.isoformat()
13 | return JSONEncoder.default(self, obj)
14 |
--------------------------------------------------------------------------------
/oabutton/static/public/css/MarkerCluster.css:
--------------------------------------------------------------------------------
1 | .leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
2 | -webkit-transition: -webkit-transform 0.2s ease-out, opacity 0.2s ease-in;
3 | -moz-transition: -moz-transform 0.2s ease-out, opacity 0.2s ease-in;
4 | -o-transition: -o-transform 0.2s ease-out, opacity 0.2s ease-in;
5 | transition: transform 0.2s ease-out, opacity 0.2s ease-in;
6 | }
--------------------------------------------------------------------------------
/oabutton/settings_local.py.example:
--------------------------------------------------------------------------------
1 | DEBUG = False
2 | TEMPLATE_DEBUG = DEBUG
3 |
4 | # API key for CORE searches
5 | CORE_API_KEY = "you need this"
6 |
7 | # Hostname to be used for bookmarklet
8 | HOSTNAME = "and this"
9 |
10 | # Amazon SES Email configuration
11 | AMAZON_SMTPHOST = "YOUR_HOST"
12 | SESSMTPUSERNAME = "YOUR_SES_SMTP_USERNAME"
13 | SESSMTPPASSWORD = "YOUR_SES_SMTP_PASSWORD"
14 |
15 | OABUTTON_EMAIL = "oabutton@crankycoder.com"
16 |
--------------------------------------------------------------------------------
/oabutton/static/public/js/compiler.sh:
--------------------------------------------------------------------------------
1 | echo "Expects compiler.jar (or symlink) in this folder"
2 | echo "See https://developers.google.com/closure/compiler/docs/gettingstarted_app"
3 | echo "--- compiling, please wait ... ---"
4 | cd lib
5 | java -jar ../compiler.jar \
6 | --warning_level QUIET \
7 | --js jquery.min.js \
8 | --js jquery.color-2.1.2.min.js \
9 | --js jquery.form.js \
10 | --js jquery.placeholder.js \
11 | --js bootstrap.min.js \
12 | --js bootstrap-dialog.js \
13 | --js leaflet.js \
14 | --js leaflet.markercluster.js \
15 | --js_output_file all.min.js
16 |
--------------------------------------------------------------------------------
/oabutton/static/test/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | OAButton JavaScript tests
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==1.5.2
2 | Jinja2==2.7.1
3 | Markdown==2.3.1
4 | MarkupSafe==0.18
5 | Pygments==1.6
6 | Sphinx==1.2b1
7 | dj-static==0.0.5
8 | django-appconf==0.6
9 | django-compressor==1.3
10 | django-filter==0.7
11 | django-mongonaut==0.2.19
12 | djangorestframework==2.3.7
13 | djangotoolbox==0.9.2
14 | docutils==0.11
15 | flake8==2.0
16 | gunicorn==18.0
17 | httplib2==0.8
18 | httpretty==0.7.0
19 | ipython==1.0.0
20 | mccabe==0.2.1
21 | mock==1.0.1
22 | mongoengine==0.8.4
23 | nose==1.3.0
24 | ordereddict==1.1
25 | pep8==1.4.6
26 | plotly==0.4
27 | pyflakes==0.7.3
28 | pyjade==2.0.3
29 | pymongo==2.6.2
30 | python-dateutil==2.2
31 | requests==2.0.0
32 | six==1.4.1
33 | static==0.4
34 | urllib3==1.7.1
35 | wsgiref==0.1.2
36 |
--------------------------------------------------------------------------------
/oabutton/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import patterns, include, url
2 |
3 | # Uncomment the next two lines to enable the admin:
4 | from django.contrib import admin
5 | admin.autodiscover()
6 |
7 | from oabutton.apps.web import views as web
8 |
9 | urlpatterns = patterns('',
10 | url(r'^$', web.homepage, name="homepage"),
11 |
12 | # I just jammed this in here while i sort out all the URL
13 | # mappings.
14 | url(r'^api/', include('oabutton.apps.bookmarklet.urls', namespace='bookmarklet')),
15 |
16 | url(r'^metadata/', include(
17 | 'oabutton.apps.metadata.urls')),
18 | )
19 |
--------------------------------------------------------------------------------
/oabutton/static/public/css/app.css:
--------------------------------------------------------------------------------
1 | IMG#bookmarklet-logo {
2 | width: 100%;
3 | }
4 |
5 | IMG#bookmarklet-badge {
6 | display: none;
7 | }
8 |
9 | .bookmarklet-footer {
10 | margin-left: 15px;
11 | margin-right: 15px;
12 | margin-top: 10px;
13 | background: "grey";
14 | font-family: "Raleway";
15 | }
16 |
17 | .raleway-font {
18 | font-family: "Raleway";
19 | }
20 |
21 | /* restyle anchor links into buttons on bookmarklet */
22 | .likeabutton {
23 | appearance: button;
24 | -moz-appearance: button;
25 | -webkit-appearance: button;
26 | color: white;
27 | text-decoration: none; font: menu; color: ButtonText;
28 | display: inline-block; padding: 2px 8px;
29 | }
30 |
31 | #email-request {
32 | margin-top: 10px;
33 | }
34 |
35 | #core_results {
36 | margin-top: 10px;
37 | margin-bottom: 10px;
38 | }
39 |
40 | form button {
41 | margin-top: 5px;
42 | }
43 |
--------------------------------------------------------------------------------
/oabutton/static/public/css/MarkerCluster.Default.css:
--------------------------------------------------------------------------------
1 | .marker-cluster-small {
2 | background-color: rgba(181, 226, 140, 0.6);
3 | }
4 | .marker-cluster-small div {
5 | background-color: rgba(110, 204, 57, 0.6);
6 | }
7 |
8 | .marker-cluster-medium {
9 | background-color: rgba(241, 211, 87, 0.6);
10 | }
11 | .marker-cluster-medium div {
12 | background-color: rgba(240, 194, 12, 0.6);
13 | }
14 |
15 | .marker-cluster-large {
16 | background-color: rgba(253, 156, 115, 0.6);
17 | }
18 | .marker-cluster-large div {
19 | background-color: rgba(241, 128, 23, 0.6);
20 | }
21 |
22 | .marker-cluster {
23 | background-clip: padding-box;
24 | border-radius: 20px;
25 | }
26 | .marker-cluster div {
27 | width: 30px;
28 | height: 30px;
29 | margin-left: 5px;
30 | margin-top: 5px;
31 |
32 | text-align: center;
33 | border-radius: 15px;
34 | font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
35 | }
36 | .marker-cluster span {
37 | line-height: 30px;
38 | }
--------------------------------------------------------------------------------
/fabfile.py:
--------------------------------------------------------------------------------
1 | """
2 | The easy button for deployment
3 |
4 | Add your SSH key :
5 |
6 | $ ssh-add ~/.ssh/oabutton.pem
7 | Identity added: /Users/victorng/.ssh/oabutton.pem (/Users/victorng/.ssh/oabutton.pem)
8 |
9 | # Run prepare_deploy:
10 |
11 | $ fab prepare_deploy
12 |
13 | # Run deploy:
14 |
15 | $ fab -H ubuntu@staging.openaccessbutton.org deploy
16 |
17 | """
18 | from fabric.api import local, settings, cd, run
19 |
20 |
21 | def prepare_deploy():
22 | local("pip install -r requirements.txt")
23 | local("make test")
24 | local("git add -p && git commit")
25 | local("git push")
26 |
27 |
28 | def deploy():
29 | code_dir = '/home/ubuntu/dev/OAButton/'
30 | with settings(warn_only=True):
31 | with cd(code_dir):
32 | run("git checkout develop")
33 | run("git pull")
34 | run("/home/ubuntu/.virtualenvs/oabutton/bin/pip install -r requirements.txt")
35 | run("sudo supervisorctl restart oabutton")
36 |
--------------------------------------------------------------------------------
/oabutton/static/public/less/forms.less:
--------------------------------------------------------------------------------
1 | .form-bookmarklet {
2 | /* max-width: 300px; */
3 | padding: 19px 29px 29px;
4 | margin: 0 auto 20px;
5 | background-color: #fff;
6 | border: 1px solid #e5e5e5;
7 | -webkit-border-radius: 5px;
8 | -moz-border-radius: 5px;
9 | border-radius: 5px;
10 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.05);
11 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.05);
12 | box-shadow: 0 1px 2px rgba(0,0,0,.05);
13 |
14 | .form-bookmarklet-heading,.checkbox {
15 | margin-bottom: 10px;
16 | }
17 |
18 | input[type="text"],
19 | input[type="password"],
20 | select
21 | {
22 | font-size: 16px;
23 | height: auto;
24 | margin-bottom: 15px;
25 | padding: 7px 9px;
26 | width: 100%;
27 | }
28 |
29 | button
30 | {
31 | font-size: 16px;
32 | height: auto;
33 | margin-bottom: 15px;
34 | padding: 7px 9px;
35 | clear: both;
36 | width: 100%;
37 | }
38 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | ---------------------
3 |
4 | Copyright (c) 2013 Open Access Button
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7 |
8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import patterns, url
2 |
3 | from views import form1, form2, form3
4 | from views import add_post
5 | from views import generate_bookmarklet
6 | from views import get_json
7 | from views import signin
8 | from views import xref_proxy
9 |
10 | urlpatterns = patterns('',
11 | # I think these 3 should be broken out to an API URL handler so we
12 | # can evolve it
13 | url(r'^$', get_json, name="get_json"),
14 |
15 | url(r'^form/page1/(?P.*)/$', form1, name="form1"),
16 | url(r'^form/page2/$', form2, name="form2"),
17 | url(r'^form/page3/$', form3, name="form3"),
18 |
19 |
20 | url(r'^post/$', add_post, name="add_post"),
21 | url(r'^signin/$', signin, name="signin"),
22 | url(r'^bookmarklet/(?P.*).js$',
23 | generate_bookmarklet,
24 | name="generate_bookmarklet"),
25 | url(r'^xref_proxy/(?P.*)',
26 | xref_proxy,
27 | name="xref_proxy"),
28 | )
29 |
--------------------------------------------------------------------------------
/oabutton/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for oabutton project.
3 |
4 | This module contains the WSGI application used by Django's development server
5 | and any production WSGI deployments. It should expose a module-level variable
6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
7 | this application via the ``WSGI_APPLICATION`` setting.
8 |
9 | Usually you will have the standard Django WSGI application here, but it also
10 | might make sense to replace the whole Django WSGI application with a custom one
11 | that later delegates to the Django one. For example, you could introduce WSGI
12 | middleware here, or combine a Django application with an application of another
13 | framework.
14 |
15 | """
16 | import os
17 |
18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oabutton.settings")
19 |
20 | from django.core.wsgi import get_wsgi_application
21 |
22 | # This application object is used by any WSGI server configured to use this
23 | # file. This includes Django's development server, if the WSGI_APPLICATION
24 | # setting points here.
25 |
26 | from dj_static import Cling
27 | application = Cling(get_wsgi_application())
28 |
29 | # Apply WSGI middleware here.
30 | # from helloworld.wsgi import HelloWorldApplication
31 | # application = HelloWorldApplication(application)
32 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5 | VAGRANTFILE_API_VERSION = "2"
6 |
7 | $PROVISION_SCRIPT = <
56 | {% endblock %}
57 | {% block body_attrs %}data-doi="{{doi|urlencode}}"{% endblock %}
58 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/templates/bookmarklet/page1.html:
--------------------------------------------------------------------------------
1 | {% extends "bookmarklet/layout.html" %}
2 | {% load oafilters %}
3 | {% block content %}
4 |
5 |
57 |
58 | {% endblock %}
59 |
60 | {% block scripts %}
61 |
62 | {% endblock %}
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/OAButton/OAButton)
3 |
4 | ## Open Access Button Prototype
5 |
6 | A prototype version of the Open Access Button idea explained in [this blog](http://oabutton.wordpress.com/2013/07/06/our-project-short-version/).
7 |
8 | #### Demo
9 |
10 | [Have a look at the demo](http://oabutton.herokuapp.com/) - however **please do not share too widely as we're pre-launch!**
11 |
12 | #### Contributing
13 |
14 | If you want to contribute, we have some [instructions for setting up your local dev environment](https://github.com/OAButton/OAButton/blob/develop/INSTRUCTIONS.md).
15 |
16 | Our code is completely open source and we invite/need developers to get involved in this amazing project. Currently we're trying to focus on attaining [our minimum viable product](https://docs.google.com/document/d/1-5NV6PoUPiB8GmxRvIO0onDnv8bV69BeDGDco9uHxik/edit) before moving into our testing phase, provisionally on 1 October 2013. That should allow us to launch on 18 November 2013, in time for the [Berlin 11 Student & Early Stage Researcher Satellite Conference](http://berlin2013.sched.org/) on the occasion of the 10th anniversary of the [Berlin Declaration on Open Access to Knowledge in the Sciences and Humanities](http://openaccess.mpg.de/286432/Berlin-Declaration)! If you have suggestions, we are more than open to them, however, and post this date, we can think about broader development.
17 |
18 | As mentioned, we're working to a tight deadline and many people are counting on this tool launching in time, so please try to work on [high priority issues](https://github.com/OAButton/OAButton/issues). Also, we discuss the projects development more broadly on our [Google Group](http://groups.google.com/group/open-access-button). Where possible open ended questions should be made here, rather than in issues.
19 |
20 | #### Elsewhere on the internet
21 |
22 | * [Blog](http://oabutton.wordpress.com/)
23 | * [Twitter](https://twitter.com/OA_Button)
24 | * [Google Group](http://groups.google.com/group/open-access-button)
25 | * [Email](mailto:oabutton@gmail.com)
26 |
27 | Licensed under the [MIT license](https://github.com/OAButton/OAButton/blob/develop/LICENSE.md). Powered by [django](https://www.djangoproject.com/) and [MongoDB](http://www.mongodb.org).
28 |
--------------------------------------------------------------------------------
/oabutton/apps/web/templates/web/layout.jade:
--------------------------------------------------------------------------------
1 | doctype 5
2 | html(lang='en', itemscope, itemtype='http://schema.org/Organization')
3 |
4 | head
5 | meta(charset='utf-8')
6 | meta(name='viewport', content='width=device-width, initial-scale=1.0')
7 | meta(http-equiv='X-UA-Compatible', content='IE=edge,chrome=1')
8 | meta(itemprop='name', content='Open Access Button')
9 | meta(itemprop='description', content='Paywalls deny people access to life-saving research every day. The Open Access Button will make the damage of paywalls visible to the world and get you access to the research you need.')
10 | meta(itemprop='image', content='/static/img/oabutton_logo.png')
11 | if title
12 | title Open Access Button - #{title}
13 | else
14 | title Open Access Button
15 | link(rel='shortcut icon', type='image/x-icon', href='/static/img/favicon.ico')
16 |
17 | link(rel='stylesheet', href='/static/css/bootstrap.min.css')
18 | link(rel='stylesheet', href='/static/css/leaflet.css')
19 | //if lte IE 8
20 | link(rel='stylesheet', href='/static/css/leaflet.ie.css')
21 | link(rel='stylesheet', type='text/css', media='all', href='/static/css/styles.css')
22 |
23 | script(src='//ajax.googleapis.com/ajax/libs/webfont/1.4.7/webfont.js')
24 | script
25 | WebFont.load({ google: { families: ['Raleway'] }});
26 | var events = {{ events|safe }};
27 |
28 | //if lt IE 9
29 | script(src='/static/js/lib/html5shiv.js')
30 | script(src='/static/js/lib/respond.min.js')
31 |
32 | body(data-spy='scroll', data-target='.navbar')
33 | block body
34 |
35 | if DEBUG
36 | script(src='/static/js/lib/jquery.min.js')
37 | script(src='/static/js/lib/jquery.color-2.1.2.min.js')
38 | script(src='/static/js/lib/jquery.form.js')
39 | script(src='/static/js/lib/jquery.placeholder.js')
40 | script(src='/static/js/lib/bootstrap.min.js')
41 | script(src='/static/js/lib/bootstrap-dialog.js')
42 | script(src='/static/js/lib/leaflet.js')
43 | script(src='/static/js/lib/leaflet.markercluster.js')
44 | else
45 | script(src='/static/js/lib/all.min.js')
46 |
47 | // Application scripts
48 | script(src='/static/js/index.js')
49 |
50 | // Analytics
51 | script
52 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
53 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
54 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
55 | })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
56 | ga('create', 'UA-43774380-1', 'openaccessbutton.org');
57 | ga('send', 'pageview');
58 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/templates/bookmarklet/page2.html:
--------------------------------------------------------------------------------
1 | {% extends "bookmarklet/layout.html" %}{% block content %}
2 |
3 |
4 | Before we try and get you access, why not share your frustration -
5 | help make this problem visible!
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | We're also on Facebook and Twitter ! Join us!
31 |
32 |
33 |
34 |
49 | {% endblock %}
50 | {% block scripts %}
51 |
52 |
59 |
66 | {% endblock %}
67 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/templates/bookmarklet/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Open Access Button
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | {% block content %}
29 | {% endblock %}
30 |
31 |
32 |
33 |
34 |
35 | {% block footer %}
36 |
49 | {% endblock %}
50 |
51 |
52 |
62 | {% block scripts %}
63 | {% endblock %}
64 |
65 |
66 |
--------------------------------------------------------------------------------
/oabutton/apps/web/templates/web/start.jade:
--------------------------------------------------------------------------------
1 | extends web/index
2 | - load oafilters
3 | block start
4 | form.form-bookmarklet#form-bookmarklet(action='/api/signin/', method='post')
5 | {% csrf_token %}
6 | .row
7 | .col-md-8.col-md-offset-2
8 | p Sign up below to get the
9 | i Open Access Button
10 | |, a safe, easy to use browser bookmarklet that you can use to show the global effects of research paywalls - and to help get access to the research you need. Every time you hit a paywall blocking your research, click the button. Fill out a short form, add your experience to the map along with thousands of others. Then use our tools to search for access to papers, and spread the word with social media. Every person who uses the
11 | i Open Access Button
12 | | brings us closer to changing the system.
13 | p
14 | a(data-toggle="modal", data-target="#video-modal", alt="Need access to research?", title="Learn more about the project in this video")
15 | | Watch the video
16 | | or
17 | a(href="http://oabutton.wordpress.com/2013/11/17/244/") read this
18 | | for a quick introduction, then sign up here:
19 | p
20 | {{ signin_form.email }}
21 | p
22 | {{ signin_form.name }}
23 | p
24 | {{ signin_form.profession }}
25 | .checkbox
26 | {{ signin_form.confirm_public}}
27 | {{ signin_form.confirm_public|label_with_classes:"confirm-label"}}
28 | .checkbox
29 | {{ signin_form.mailinglist}}
30 | {{ signin_form.mailinglist|label_with_classes:"mailinglist-label"}}
31 | p Your e-mail address
32 | u will not
33 | | be publicised or shared with third parties.
34 | p
35 | div.form-group
36 | {{ signin_form.privacy}}
37 | button.btn.btn-lg.btn-primary.btn-block(type='submit')
38 | | Get my personal Open Access Button
39 |
40 | #bookmarklet(style='display:none')
41 | .content
42 | i.wedge-up
43 | p
44 | | Drag me to your bookmark bar:
45 | a.btn.btn-lg.btn-primary
46 | i.icon-bookmark Open Access Button
47 |
48 | #help-bookmarklet
49 | .row
50 | .col-md-8.col-md-offset-2
51 | p
52 | b Thanks for signing up!
53 | | Don't forget to check your inbox for a verification email.
54 | p If you do not see a bookmark bar at the top of your browser, you can find instructions for activating yours here:
55 | a(href="https://support.google.com/chrome/answer/95745") Chrome
56 | |,
57 | a(href="http://support.mozilla.org/en-US/kb/bookmarks-toolbar-display-favorite-websites") Firefox
58 | |,
59 | a(href="http://support.apple.com/kb/ph4967") Safari
60 | |,
61 | a(href="http://www.cultofmac.com/36839/enabling-and-adding-to-the-bookmarks-bar-in-safari-for-ipad-how-to/") iPad
62 | |,
63 | a(href="http://windows.microsoft.com/en-us/windows-vista/show-or-hide-the-favorites-bar-in-internet-explorer-8") Internet Explorer
64 | |. For a 2-minute walkthrough on using the button (don't worry, it's easy!) -
65 | a(href="#start", data-dismiss="modal", data-toggle="modal", data-target="#video-modal") watch this video
66 | | or
67 | a(href="http://oabutton.wordpress.com/2013/11/17/244/") read here
68 | |.
69 |
--------------------------------------------------------------------------------
/INSTRUCTIONS.md:
--------------------------------------------------------------------------------
1 | ## Getting started
2 |
3 | ### Requirements
4 |
5 | * [Python 2.6 or Python 2.7](http://www.python.org/getit/)
6 | * [pip](http://www.pip-installer.org/en/latest/installing.html)
7 | * [mongodb](http://docs.mongodb.org/manual/installation/)
8 | * [virtualenv](https://pypi.python.org/pypi/virtualenv) (optional but
9 | recommended)
10 |
11 | ### Installing
12 |
13 | Clone the [git repository][repo] and set up:
14 | ```
15 | git clone https://github.com/OAButton/OAButton.git /path/to/repo
16 | cd /path/to/repo # Switch to the directory where
17 | # you've cloned the repo
18 | git checkout develop # Switch to the develop branch
19 |
20 | virtualenv oab-env # Set up a new virtualenv (optional)
21 | . oab-env/bin/activate # Activate the virtualenv (optional)
22 |
23 | pip install -r requirements.txt # Install dependencies
24 |
25 | flake8 --install-hook # Install the flake8 pre-commit hook
26 | # Checks your code for PEP8 compliance
27 | ```
28 |
29 | ### Set your CORE API key
30 |
31 | ```
32 | export CORE_API_KEY=blahblahblah
33 | ```
34 |
35 | If you don't have a key, the app will still run, but you'll get
36 | warnings and communications with [CORE](http://core.kmi.open.ac.uk/)
37 | will fail. An API key isn't required to run the tests, as the API
38 | accesses are mocked out.
39 |
40 | ### Start mongodb
41 |
42 | If the mongodb daemon is not running yet, you can start it locally with
43 | ```
44 | mongod --smallfiles -v
45 | ```
46 |
47 | If you have installed MongoDB via your Debian/Ubuntu package mangager, do
48 | ```
49 | sudo service mongodb start
50 | ```
51 |
52 | ### Synchronise the database
53 |
54 | This will set up the database ready to use. You only have to do this once:
55 | ```
56 | python manage.py syncdb
57 | ```
58 | You will be prompted to create a superuser. Reply yes and follow the
59 | instructions.
60 |
61 |
62 | ### Start the webserver
63 |
64 | ```
65 | python manage.py runserver
66 | ```
67 |
68 | * Visit . Hooray!
69 |
70 | ### Development
71 |
72 | Use of virtualenv is highly recommended for development - it will
73 | ensure that all contributors are using a consistent set of packages.
74 |
75 | * You must be in your virtualenv before you start hacking on oabutton.
76 | * Remember to activate your virtualenv using (`source env/bin/activate`).
77 | * Check in settings.py that the line `from settings_local import *`
78 | is not commented out
79 |
80 | We are using LESSC to compile stylesheets from LESS to CSS. The compiler is
81 | run from a Makefile. Install Node.js then `npm install lessc -g`, then run
82 | `make` from the root folder to update CSS.
83 |
84 | ### Running the tests
85 |
86 | From the directory with the file manage.py in it
87 | ```
88 | python manage.py test bookmarklet web
89 | ```
90 |
91 | ### Heroku deployment
92 |
93 | * Ensure that settings.py imports from settings_heroku.py
94 | * Initial Postgresql Syncing of the database is done with: `heroku run python manage.py syncdb`
95 | * See: https://devcenter.heroku.com/articles/getting-started-with-django
96 |
97 | Required enviroment variables
98 |
99 | ## Getting started with a virtual machine
100 |
101 | If you're familiar with [Vagrant](http://vagrantup.com/) and virtual
102 | machines, there's a Vagrantfile included which will set up and
103 | provision a development VM for you.
104 |
105 | If you're not familiar, here's a lightning tutorial. After installing
106 | VirtualBox and Vagrant, and cloning the [git repository][repo]:
107 |
108 | 1. Open a command line and change to the directory where you cloned
109 | the repository
110 | 2. Start up the virtual machine: `vagrant up`
111 | * This will take a while the first time you do it, while it
112 | downloads the machine image and installs various prerequisites.
113 | 3. Log into the virtual machine via SSH: `vagrant ssh`
114 | * You should now have a commandline open in your virtual machine.
115 | 4. Change to the vagrant shared directory: `cd /vagrant`
116 | * The repository you cloned will automatically be mounted at
117 | `/vagrant`, so you can edit the files there using your favourite
118 | text editor *outside the VM* and all changes will be visible
119 | inside the VM as well. Just restart the server when you need
120 | to.
121 | 5. Activate the virtualenv environment: `source env/bin/activate`
122 | 6. Start the development server: `python manage.py runserver
123 | 192.168.33.10:8000`
124 | * Note the IP address on the end: if you omit this,
125 | 7. Point your web browser to
126 |
127 | When you've finished working, you can quit the webserver if it's still
128 | running (`CTRL-C`), log out of the virtual machine (`exit`) and then
129 | either:
130 |
131 | * Shut down the VM: `vagrant halt`
132 | * Suspend the VM to disk: `vagrant suspend`
133 |
134 | Then next time you're ready to work, follow the instructions above
135 | again: step 2 will take much less time as the VM is already installed
136 | and configured and just needs to boot.
137 |
138 | If you ever need to completely reset the VM, just delete it with
139 | `vagrant destroy` and start again.
140 |
141 | [repo]: http://github.com/OAButton/OAButton
142 |
--------------------------------------------------------------------------------
/oabutton/static/public/js/success.js:
--------------------------------------------------------------------------------
1 | // This is just for successful submission to generate the xref links
2 | var oabSuccess = (function($) {
3 |
4 | function parseCrossRef(entry, doi) {
5 | var metadata = {'doi': doi},
6 | item = entry["pam:message"]["pam:article"];
7 |
8 | if (item["dc:title"]) {
9 | metadata["title"] = item["dc:title"];
10 | }
11 |
12 | if (item["dc:creator"]) {
13 | if (!$.isArray(item["dc:creator"])) {
14 | item["dc:creator"] = [item["dc:creator"]];
15 | }
16 |
17 | metadata["authors"] = item["dc:creator"].join(", ");
18 | }
19 |
20 | if (item["prism:publicationName"]) {
21 | metadata["publication"] = item["prism:publicationName"];
22 | }
23 |
24 | if (item["prism:publicationDate"]) {
25 | // TODO: zero-pad or reformat the date, using Moment.js?
26 | metadata["date"] = item["prism:publicationDate"];
27 | }
28 |
29 | return metadata;
30 | }
31 |
32 | function lookupCrossRef() {
33 | var doi = $('body').data('doi');
34 |
35 | if (doi) {
36 | $.ajax({
37 | url: 'http://data.crossref.org/' + encodeURIComponent(doi),
38 | dataType: "json",
39 | success: function(response) {
40 | if (response.feed.entry) {
41 | var metadata = parseCrossRef(response.feed.entry, doi);
42 |
43 | addPubMedCentralLink(metadata);
44 | addScholarDOILink(metadata);
45 | addScholarTitleLink(metadata);
46 | discoverCORELinks(metadata);
47 | }
48 | }
49 | });
50 | }
51 | }
52 |
53 | function addPubMedCentralLink(metadata) {
54 | var doi = metadata["doi"];
55 |
56 | if (doi) {
57 | $.ajax({
58 | url: 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi',
59 | data: {
60 | db: "pmc",
61 | retmax: 1,
62 | term: doi + "[DOI]",
63 | tool: "oabutton"
64 | },
65 | dataType: "xml",
66 | success: function(response) {
67 | if (response.getElementsByTagName('Count')[0].textContent === '0') {
68 | return;
69 | }
70 |
71 | var pmcid = response.getElementsByTagName('Id')[0].textContent;
72 | var url = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" + pmcid + "/";
73 | var pmc_link = document.createElement("a");
74 | pmc_link.setAttribute("class", "likeabutton btn btn-primary btn-block")
75 | pmc_link.setAttribute("href", url);
76 | pmc_link.setAttribute("target", "_blank");
77 | pmc_link.innerHTML = "View on PubMedCentral";
78 |
79 |
80 | $("#pmc_links").append(pmc_link);
81 | }
82 | });
83 | }
84 | }
85 |
86 | function addScholarDOILink(metadata) {
87 | var doi = metadata["doi"];
88 |
89 | if (doi) {
90 | var url = 'http://scholar.google.com/scholar?cluster=' + encodeURIComponent('http://dx.doi.org/' + doi);
91 |
92 | var sch_link = document.createElement("a");
93 | sch_link.setAttribute("class", "btn btn-primary btn-block")
94 | sch_link.setAttribute("href", url);
95 | sch_link.setAttribute("target", "_blank");
96 | sch_link.innerHTML = "Search Google Scholar by DOI";
97 |
98 | $("#google_links").append(sch_link);
99 | }
100 | }
101 |
102 | function addScholarTitleLink(metadata) {
103 | var title = metadata["title"];
104 |
105 | if (title) {
106 | var url = 'http://scholar.google.com/scholar?as_occt=title&as_q=' + encodeURIComponent(title);
107 |
108 | var sch_link = document.createElement("a");
109 | sch_link.setAttribute("class", "btn btn-primary btn-block")
110 | sch_link.setAttribute("href", url);
111 | sch_link.setAttribute("target", "_blank");
112 | sch_link.innerHTML = "Search Google Scholar by title";
113 |
114 | $("#google_links").append(sch_link);
115 | }
116 | }
117 |
118 | function discoverCORELinks(metadata) {
119 | var title = metadata["title"];
120 |
121 | if (title) {
122 | $.ajax({
123 | url: "/metadata/coresearch.json/title:(" + encodeURIComponent(title) + ")",
124 | dataType: 'json',
125 | success: function(response) {
126 | var records = response.ListRecords;
127 | var $list = $('');
128 | for (var i = 1; i < records.length; i++) {
129 | metadata = records[i]['record']['metadata']['oai_dc:dc'];
130 | $list.append(''
133 | + metadata['dc:creator']
134 | + ' (' + metadata['dc:date'] + '); '
135 | + metadata['dc:title']
136 | + ' ');
137 | }
138 |
139 | $core_div = $('Matches from the
CORE repository:
');
140 | $core_div.append($list);
141 | $("#core_links").append($core_div);
142 | }
143 | });
144 | }
145 | }
146 |
147 | return {
148 | parseCrossRef: parseCrossRef,
149 | lookupCrossRef: lookupCrossRef,
150 | addScholarDOILink: addScholarDOILink,
151 | addScholarTitleLink: addScholarTitleLink,
152 | discoverCORELinks: discoverCORELinks,
153 | };
154 |
155 | })(jQuery);
156 |
157 |
158 | $(document).ready(function() {
159 | oabSuccess.lookupCrossRef();
160 | });
161 |
--------------------------------------------------------------------------------
/oabutton/apps/metadata/tests.py:
--------------------------------------------------------------------------------
1 | """
2 | This file demonstrates writing tests using the unittest module. These will pass
3 | when you run "manage.py test".
4 |
5 | Replace this with more appropriate tests for your application.
6 | """
7 |
8 | from django.test import TestCase
9 | from django.test.client import Client
10 | import httpretty
11 | import os
12 | import json
13 |
14 |
15 | SAMPLE_ARTHRITIS = r'''{"ListRecords":[{"total_hits":5015},{"record":{"header":{"header:content":{"core:repositoryIdentifier":"143","identifier":"669636"},"header:attr":{"xmlns:core":"http:\/\/core.kmi.open.ac.uk\/api\/doc"}},"metadata":{"oai_dc:dc":{"oai_dc:ns":[{"xmlns:oai_dc":"http:\/\/www.openarchives.org\/OAI\/2.0\/oai_dc\/","xmlns:dc":"http:\/\/purl.org\/dc\/elements\/1.1\/"}],"dc:creator":"R Kudyar","dc:format":"application\/pdf","dc:source":"http:\/\/www.jkscience.org\/archive\/111\/18-RL-JACORD%20ARTHRITIS.pdf","dc:date":"2009","dc:identifier":"http:\/\/www.jkscience.org\/archive\/111\/18-RL-JACORD%20ARTHRITIS.pdf","dc:description":"A case of a patient with rheumatic valvulardisease who had comparable deformities of the handsand fingers and who fulfilled all of the criteriasuggested by Bywaters to describe Jaccoud's Arthritis is decribed here.","dc:title":"Jaccoud\u2019s Arthritis"}}}},{"record":{"header":{"header:content":{"core:repositoryIdentifier":"140","identifier":"60225"},"header:attr":{"xmlns:core":"http:\/\/core.kmi.open.ac.uk\/api\/doc"}},"metadata":{"oai_dc:dc":{"oai_dc:ns":[{"xmlns:oai_dc":"http:\/\/www.openarchives.org\/OAI\/2.0\/oai_dc\/","xmlns:dc":"http:\/\/purl.org\/dc\/elements\/1.1\/"}],"dc:creator":"Zai Liu, Guo Deng, Simon Foster and Andrej Tarkowski","dc:format":"application\/pdf","dc:source":"http:\/\/eprints.whiterose.ac.uk\/21\/1\/ar330.pdf","dc:date":"2001-09-17","dc:identifier":"http:\/\/eprints.whiterose.ac.uk\/21\/1\/ar330.pdf","dc:description":"Staphylococcus aureus is one of the most important pathogens in septic arthritis. To analyse the arthritogenic properties of staphylococcal peptidoglycan (PGN), highly purified PGN from S. aureus was intra-articularly injected into murine joints. The results demonstrate that PGN will trigger arthritis in a dose-dependent manner. A single injection of this compound leads to massive infiltration of predominantly macrophages and polymorphonuclear cells with occasional signs of cartilage and\/or bone destruction, lasting for at least 14 days. Further studies showed that this condition is mediated by the combined impact of acquired and innate immune systems. Our results indicate that PGN exerts a central role in joint inflammation triggered by S. aureus.","dc:title":"Staphylococcal peptidoglycans induce arthritis"}}}},{"record":{"header":{"header:content":{"core:repositoryIdentifier":"143","identifier":"5726004"},"header:attr":{"xmlns:core":"http:\/\/core.kmi.open.ac.uk\/api\/doc"}},"metadata":{"oai_dc:dc":{"oai_dc:ns":[{"xmlns:oai_dc":"http:\/\/www.openarchives.org\/OAI\/2.0\/oai_dc\/","xmlns:dc":"http:\/\/purl.org\/dc\/elements\/1.1\/"}],"dc:creator":"Karambin Mohammad Mehdi and Hashemian Hooman","dc:format":"application\/pdf","dc:source":"http:\/\/journals.tums.ac.ir\/PdfMed.aspx?pdf_med=\/upload_files\/pdf\/12751.pdf&manuscript_id=12751","dc:date":"2009","dc:identifier":"http:\/\/journals.tums.ac.ir\/PdfMed.aspx?pdf_med=\/upload_files\/pdf\/12751.pdf&manuscript_id=12751","dc:description":"To determine the rate of different types of arthritis in children. We prepared a retrospective descriptive study and included the whole 100 cases of arthritis referred to 17-Shahrivar Hospital, Rasht, Guilan during a 3 years period. Using their medical files, data including age, sex, season of admission, history of trauma, signs and symptoms, lab findings and duration of hospitalization were collected. SPSS 13.0 (statistical software) applied for statistical analysis. The most common age of involvement ranged 6-9 years. Septic arthritis, brucellosis, and rheumatoid fever were the most frequent causes of arthritis in our study. Fever and restricted range of motion had the highest rate among different signs and symptoms. Lab data demonstrated leukocytosis, positive CRP, and increased ESR among 74, 79.5, and 73 percent of our patients, respectively. According to the high prevalence of septic arthritis and the arthritis due to brucellosis and rheumatoid fever, it seems that mentioned diseases are still major problems in the issue of hygiene management.","dc:title":"Childhood Arthritis: Rate of Different Types"}}}}]}'''
16 |
17 |
18 | class SimpleTest(TestCase):
19 |
20 | def setUp(self):
21 | os.environ['CORE_API_KEY'] = 'Not really an API key'
22 |
23 | @httpretty.activate
24 | def test_core_search_success(self):
25 | """
26 | Test that a successful request is proxied correctly
27 | """
28 | httpretty.register_uri(
29 | httpretty.GET,
30 | "http://core.kmi.open.ac.uk/api/search/arthritis",
31 | body=SAMPLE_ARTHRITIS)
32 |
33 | c = Client()
34 | response = c.get('/metadata/coresearch.json/arthritis')
35 |
36 | self.assertEqual(response.status_code, 200)
37 | self.assertEqual(response.content, SAMPLE_ARTHRITIS)
38 |
39 | @httpretty.activate
40 | def test_core_search_failure(self):
41 | """
42 | Test that a failed request is passed on
43 | """
44 | httpretty.register_uri(
45 | httpretty.GET,
46 | "http://core.kmi.open.ac.uk/api/search/arthritis",
47 | body='ERROR',
48 | status=418)
49 |
50 | c = Client()
51 | response = c.get('/metadata/coresearch.json/arthritis')
52 |
53 | self.assertEqual(response.status_code, 502)
54 |
55 | response_info = json.loads(response.content)
56 | self.assertTrue('error' in response_info)
57 | self.assertEqual(response_info['error']['status'], 418)
58 | self.assertEqual(response_info['error']['content'], 'ERROR')
59 |
--------------------------------------------------------------------------------
/oabutton/static/test/resources/qunit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * QUnit v1.12.0 - A JavaScript Unit Testing Framework
3 | *
4 | * http://qunitjs.com
5 | *
6 | * Copyright 2012 jQuery Foundation and other contributors
7 | * Released under the MIT license.
8 | * http://jquery.org/license
9 | */
10 |
11 | /** Font Family and Sizes */
12 |
13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
15 | }
16 |
17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
18 | #qunit-tests { font-size: smaller; }
19 |
20 |
21 | /** Resets */
22 |
23 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
24 | margin: 0;
25 | padding: 0;
26 | }
27 |
28 |
29 | /** Header */
30 |
31 | #qunit-header {
32 | padding: 0.5em 0 0.5em 1em;
33 |
34 | color: #8699a4;
35 | background-color: #0d3349;
36 |
37 | font-size: 1.5em;
38 | line-height: 1em;
39 | font-weight: normal;
40 |
41 | border-radius: 5px 5px 0 0;
42 | -moz-border-radius: 5px 5px 0 0;
43 | -webkit-border-top-right-radius: 5px;
44 | -webkit-border-top-left-radius: 5px;
45 | }
46 |
47 | #qunit-header a {
48 | text-decoration: none;
49 | color: #c2ccd1;
50 | }
51 |
52 | #qunit-header a:hover,
53 | #qunit-header a:focus {
54 | color: #fff;
55 | }
56 |
57 | #qunit-testrunner-toolbar label {
58 | display: inline-block;
59 | padding: 0 .5em 0 .1em;
60 | }
61 |
62 | #qunit-banner {
63 | height: 5px;
64 | }
65 |
66 | #qunit-testrunner-toolbar {
67 | padding: 0.5em 0 0.5em 2em;
68 | color: #5E740B;
69 | background-color: #eee;
70 | overflow: hidden;
71 | }
72 |
73 | #qunit-userAgent {
74 | padding: 0.5em 0 0.5em 2.5em;
75 | background-color: #2b81af;
76 | color: #fff;
77 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
78 | }
79 |
80 | #qunit-modulefilter-container {
81 | float: right;
82 | }
83 |
84 | /** Tests: Pass/Fail */
85 |
86 | #qunit-tests {
87 | list-style-position: inside;
88 | }
89 |
90 | #qunit-tests li {
91 | padding: 0.4em 0.5em 0.4em 2.5em;
92 | border-bottom: 1px solid #fff;
93 | list-style-position: inside;
94 | }
95 |
96 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
97 | display: none;
98 | }
99 |
100 | #qunit-tests li strong {
101 | cursor: pointer;
102 | }
103 |
104 | #qunit-tests li a {
105 | padding: 0.5em;
106 | color: #c2ccd1;
107 | text-decoration: none;
108 | }
109 | #qunit-tests li a:hover,
110 | #qunit-tests li a:focus {
111 | color: #000;
112 | }
113 |
114 | #qunit-tests li .runtime {
115 | float: right;
116 | font-size: smaller;
117 | }
118 |
119 | .qunit-assert-list {
120 | margin-top: 0.5em;
121 | padding: 0.5em;
122 |
123 | background-color: #fff;
124 |
125 | border-radius: 5px;
126 | -moz-border-radius: 5px;
127 | -webkit-border-radius: 5px;
128 | }
129 |
130 | .qunit-collapsed {
131 | display: none;
132 | }
133 |
134 | #qunit-tests table {
135 | border-collapse: collapse;
136 | margin-top: .2em;
137 | }
138 |
139 | #qunit-tests th {
140 | text-align: right;
141 | vertical-align: top;
142 | padding: 0 .5em 0 0;
143 | }
144 |
145 | #qunit-tests td {
146 | vertical-align: top;
147 | }
148 |
149 | #qunit-tests pre {
150 | margin: 0;
151 | white-space: pre-wrap;
152 | word-wrap: break-word;
153 | }
154 |
155 | #qunit-tests del {
156 | background-color: #e0f2be;
157 | color: #374e0c;
158 | text-decoration: none;
159 | }
160 |
161 | #qunit-tests ins {
162 | background-color: #ffcaca;
163 | color: #500;
164 | text-decoration: none;
165 | }
166 |
167 | /*** Test Counts */
168 |
169 | #qunit-tests b.counts { color: black; }
170 | #qunit-tests b.passed { color: #5E740B; }
171 | #qunit-tests b.failed { color: #710909; }
172 |
173 | #qunit-tests li li {
174 | padding: 5px;
175 | background-color: #fff;
176 | border-bottom: none;
177 | list-style-position: inside;
178 | }
179 |
180 | /*** Passing Styles */
181 |
182 | #qunit-tests li li.pass {
183 | color: #3c510c;
184 | background-color: #fff;
185 | border-left: 10px solid #C6E746;
186 | }
187 |
188 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
189 | #qunit-tests .pass .test-name { color: #366097; }
190 |
191 | #qunit-tests .pass .test-actual,
192 | #qunit-tests .pass .test-expected { color: #999999; }
193 |
194 | #qunit-banner.qunit-pass { background-color: #C6E746; }
195 |
196 | /*** Failing Styles */
197 |
198 | #qunit-tests li li.fail {
199 | color: #710909;
200 | background-color: #fff;
201 | border-left: 10px solid #EE5757;
202 | white-space: pre;
203 | }
204 |
205 | #qunit-tests > li:last-child {
206 | border-radius: 0 0 5px 5px;
207 | -moz-border-radius: 0 0 5px 5px;
208 | -webkit-border-bottom-right-radius: 5px;
209 | -webkit-border-bottom-left-radius: 5px;
210 | }
211 |
212 | #qunit-tests .fail { color: #000000; background-color: #EE5757; }
213 | #qunit-tests .fail .test-name,
214 | #qunit-tests .fail .module-name { color: #000000; }
215 |
216 | #qunit-tests .fail .test-actual { color: #EE5757; }
217 | #qunit-tests .fail .test-expected { color: green; }
218 |
219 | #qunit-banner.qunit-fail { background-color: #EE5757; }
220 |
221 |
222 | /** Result */
223 |
224 | #qunit-testresult {
225 | padding: 0.5em 0.5em 0.5em 2.5em;
226 |
227 | color: #2b81af;
228 | background-color: #D2E0E6;
229 |
230 | border-bottom: 1px solid white;
231 | }
232 | #qunit-testresult .module-name {
233 | font-weight: bold;
234 | }
235 |
236 | /** Fixture */
237 |
238 | #qunit-fixture {
239 | position: absolute;
240 | top: -10000px;
241 | left: -10000px;
242 | width: 1000px;
243 | height: 1000px;
244 | }
245 |
--------------------------------------------------------------------------------
/oabutton/static/public/js/lib/jquery.placeholder.js:
--------------------------------------------------------------------------------
1 | /*! http://mths.be/placeholder v2.0.7 by @mathias */
2 | ;(function(window, document, $) {
3 |
4 | var isInputSupported = 'placeholder' in document.createElement('input');
5 | var isTextareaSupported = 'placeholder' in document.createElement('textarea');
6 | var prototype = $.fn;
7 | var valHooks = $.valHooks;
8 | var propHooks = $.propHooks;
9 | var hooks;
10 | var placeholder;
11 |
12 | if (isInputSupported && isTextareaSupported) {
13 |
14 | placeholder = prototype.placeholder = function() {
15 | return this;
16 | };
17 |
18 | placeholder.input = placeholder.textarea = true;
19 |
20 | } else {
21 |
22 | placeholder = prototype.placeholder = function() {
23 | var $this = this;
24 | $this
25 | .filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]')
26 | .not('.placeholder')
27 | .bind({
28 | 'focus.placeholder': clearPlaceholder,
29 | 'blur.placeholder': setPlaceholder
30 | })
31 | .data('placeholder-enabled', true)
32 | .trigger('blur.placeholder');
33 | return $this;
34 | };
35 |
36 | placeholder.input = isInputSupported;
37 | placeholder.textarea = isTextareaSupported;
38 |
39 | hooks = {
40 | 'get': function(element) {
41 | var $element = $(element);
42 |
43 | var $passwordInput = $element.data('placeholder-password');
44 | if ($passwordInput) {
45 | return $passwordInput[0].value;
46 | }
47 |
48 | return $element.data('placeholder-enabled') && $element.hasClass('placeholder') ? '' : element.value;
49 | },
50 | 'set': function(element, value) {
51 | var $element = $(element);
52 |
53 | var $passwordInput = $element.data('placeholder-password');
54 | if ($passwordInput) {
55 | return $passwordInput[0].value = value;
56 | }
57 |
58 | if (!$element.data('placeholder-enabled')) {
59 | return element.value = value;
60 | }
61 | if (value == '') {
62 | element.value = value;
63 | // Issue #56: Setting the placeholder causes problems if the element continues to have focus.
64 | if (element != safeActiveElement()) {
65 | // We can't use `triggerHandler` here because of dummy text/password inputs :(
66 | setPlaceholder.call(element);
67 | }
68 | } else if ($element.hasClass('placeholder')) {
69 | clearPlaceholder.call(element, true, value) || (element.value = value);
70 | } else {
71 | element.value = value;
72 | }
73 | // `set` can not return `undefined`; see http://jsapi.info/jquery/1.7.1/val#L2363
74 | return $element;
75 | }
76 | };
77 |
78 | if (!isInputSupported) {
79 | valHooks.input = hooks;
80 | propHooks.value = hooks;
81 | }
82 | if (!isTextareaSupported) {
83 | valHooks.textarea = hooks;
84 | propHooks.value = hooks;
85 | }
86 |
87 | $(function() {
88 | // Look for forms
89 | $(document).delegate('form', 'submit.placeholder', function() {
90 | // Clear the placeholder values so they don't get submitted
91 | var $inputs = $('.placeholder', this).each(clearPlaceholder);
92 | setTimeout(function() {
93 | $inputs.each(setPlaceholder);
94 | }, 10);
95 | });
96 | });
97 |
98 | // Clear placeholder values upon page reload
99 | $(window).bind('beforeunload.placeholder', function() {
100 | $('.placeholder').each(function() {
101 | this.value = '';
102 | });
103 | });
104 |
105 | }
106 |
107 | function args(elem) {
108 | // Return an object of element attributes
109 | var newAttrs = {};
110 | var rinlinejQuery = /^jQuery\d+$/;
111 | $.each(elem.attributes, function(i, attr) {
112 | if (attr.specified && !rinlinejQuery.test(attr.name)) {
113 | newAttrs[attr.name] = attr.value;
114 | }
115 | });
116 | return newAttrs;
117 | }
118 |
119 | function clearPlaceholder(event, value) {
120 | var input = this;
121 | var $input = $(input);
122 | if (input.value == $input.attr('placeholder') && $input.hasClass('placeholder')) {
123 | if ($input.data('placeholder-password')) {
124 | $input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));
125 | // If `clearPlaceholder` was called from `$.valHooks.input.set`
126 | if (event === true) {
127 | return $input[0].value = value;
128 | }
129 | $input.focus();
130 | } else {
131 | input.value = '';
132 | $input.removeClass('placeholder');
133 | input == safeActiveElement() && input.select();
134 | }
135 | }
136 | }
137 |
138 | function setPlaceholder() {
139 | var $replacement;
140 | var input = this;
141 | var $input = $(input);
142 | var id = this.id;
143 | if (input.value == '') {
144 | if (input.type == 'password') {
145 | if (!$input.data('placeholder-textinput')) {
146 | try {
147 | $replacement = $input.clone().attr({ 'type': 'text' });
148 | } catch(e) {
149 | $replacement = $(' ').attr($.extend(args(this), { 'type': 'text' }));
150 | }
151 | $replacement
152 | .removeAttr('name')
153 | .data({
154 | 'placeholder-password': $input,
155 | 'placeholder-id': id
156 | })
157 | .bind('focus.placeholder', clearPlaceholder);
158 | $input
159 | .data({
160 | 'placeholder-textinput': $replacement,
161 | 'placeholder-id': id
162 | })
163 | .before($replacement);
164 | }
165 | $input = $input.removeAttr('id').hide().prev().attr('id', id).show();
166 | // Note: `$input[0] != input` now!
167 | }
168 | $input.addClass('placeholder');
169 | $input[0].value = $input.attr('placeholder');
170 | } else {
171 | $input.removeClass('placeholder');
172 | }
173 | }
174 |
175 | function safeActiveElement() {
176 | // Avoid IE9 `document.activeElement` of death
177 | // https://github.com/mathiasbynens/jquery-placeholder/pull/99
178 | try {
179 | return document.activeElement;
180 | } catch (err) {}
181 | }
182 |
183 | }(this, document, jQuery));
184 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/templates/bookmarklet/bookmarklet.html:
--------------------------------------------------------------------------------
1 | (function() {
2 | // Detect a DOI for the article
3 | var detectDOI = function() {
4 | var nodes, node, childNode, matches, i, j;
5 |
6 | // match DOI: test on http://t.co/eIJciunBRJ
7 | var doi_re = /\b10\.\d{4,}(?:\.\d+)*\/\S+\b/;
8 |
9 | // look for meta[name=citation_doi][content]
10 | nodes = document.getElementsByTagName("meta");
11 | for (i = 0; i < nodes.length; i++) {
12 | node = nodes[i];
13 |
14 | if (node.getAttribute("name") == "citation_doi") {
15 | return node.getAttribute("content").replace(/^doi:/, "");
16 | }
17 | }
18 |
19 | // look in all text nodes for a DOI
20 | nodes = document.getElementsByTagName("*");
21 | for (i = 0; i < nodes.length; i++) {
22 | node = nodes[i];
23 |
24 | if (!node.hasChildNodes()) {
25 | continue;
26 | }
27 |
28 | if (node.nodeName == "SCRIPT") {
29 | continue;
30 | }
31 |
32 | for (j = 0; j < node.childNodes.length; j++) {
33 | childNode = node.childNodes[j];
34 |
35 | // only text nodes
36 | if (childNode.nodeType !== 3) {
37 | continue;
38 | }
39 |
40 | if (matches = doi_re.exec(childNode.nodeValue)) {
41 | return matches[0];
42 | }
43 | }
44 | }
45 |
46 | return null;
47 | };
48 |
49 | // Detect an email address for the corresponding author.
50 | var detectAuthorEmail = function() {
51 | var nodes, node, matches, i;
52 |
53 | // match email address in mailto link
54 | // from http://stackoverflow.com/a/201447/145899
55 | var mailto_re = /^mailto:(\S+@\S+\.\S+)/;
56 |
57 | // look for meta[name=citation_author_email][content]
58 | // test on http://dx.doi.org/10.1007/978-3-642-02879-3_7
59 | nodes = document.getElementsByTagName("meta");
60 | for (i = 0; i < nodes.length; i++) {
61 | node = nodes[i];
62 |
63 | if (node.getAttribute("name") == "citation_author_email") {
64 | return node.getAttribute("content");
65 | }
66 | }
67 |
68 | // look for links that start with "mailto:".
69 | // can't guarantee this is the author - might be an editor or support email.
70 | // test on http://dx.doi.org/10.1371/journal.pone.0052814
71 | nodes = document.getElementsByTagName("a");
72 | for (i = 0; i < nodes.length; i++) {
73 | node = nodes[i];
74 |
75 | if (matches = mailto_re.exec(node.getAttribute("href"))) {
76 | return matches[1].replace(/\?.*/, ""); // remove any query string
77 | }
78 | }
79 |
80 | return null;
81 | };
82 |
83 | // ascertain if the bookmarklet has already been called
84 | var exists = document.getElementById("OAButton");
85 | var email = detectAuthorEmail();
86 | console.log("Got email: " + email);
87 |
88 | if(exists == null)
89 | {
90 |
91 | // get the base URL
92 | var loader = document.body.lastChild;
93 | var base = loader.getAttribute("src").match(/^https?:\/\/[^/]+/)[0];
94 | loader.parentNode.removeChild(loader);
95 |
96 | // build the iframe URL
97 | // Custom URL for user: [{{user_id}}]
98 | var url = base + "/api/form/page1/{{ user_id }}/?url=" + encodeURIComponent(window.location);
99 | var doi = detectDOI();
100 | if(doi) {
101 | url += "&doi=" + encodeURIComponent(doi);
102 | }
103 | if (email) {
104 | url += "&email=" + encodeURIComponent(email);
105 | }
106 |
107 | // build the control div
108 | var div = document.createElement("div");
109 | div.setAttribute("allowTransparency", "true");
110 | div.setAttribute("id", "OAButton");
111 |
112 | div.style.position = "fixed";
113 | div.style.zIndex = "2147483640";
114 | div.style.boxSizing = "border-box";
115 | div.style.MozBoxSizing = "border-box";
116 | div.style.padding = "15px";
117 | div.style.background = "white";
118 | div.style.height = "100%";
119 | div.style.width = "350px";
120 | div.style.top = "0";
121 | div.style.right = "0";
122 | div.style.overflow = "scroll";
123 | div.style.overflowX = "hidden";
124 |
125 | document.body.appendChild(div);
126 |
127 | // add the close button
128 | var closeButton = document.createElement("a");
129 | closeButton.setAttribute("href", "javascript:document.getElementById('OAButton').setAttribute('style', 'display:none')");
130 | closeButton.setAttribute("id", "closeButton");
131 | closeButton.appendChild(document.createTextNode("X"));
132 | closeButton.style.zIndex = "2147483641";
133 | closeButton.style.position = "relative";
134 | closeButton.style.top = "0";
135 |
136 | div.appendChild(closeButton);
137 |
138 | // add the iframe
139 | var iframe = document.createElement("iframe");
140 | iframe.setAttribute("allowTransparency", "true");
141 | iframe.setAttribute("src", url);
142 |
143 | iframe.style.position = "fixed";
144 | iframe.style.zIndex = "2147483640";
145 | iframe.style.boxSizing = "border-box";
146 | iframe.style.MozBoxSizing = "border-box";
147 | iframe.style.padding = "15px";
148 | iframe.style.borderLeft = "2px #555 dashed";
149 | iframe.style.background = "white";
150 | iframe.style.height = "100%";
151 | iframe.style.width = "350px";
152 | iframe.style.bottom = "0";
153 | iframe.style.right = "0";
154 |
155 | div.appendChild(iframe);
156 | } else {
157 | var div = exists;
158 | div.setAttribute("allowTransparency", "true");
159 | div.setAttribute("id", "OAButton");
160 |
161 | div.style.position = "fixed";
162 | div.style.zIndex = "2147483640";
163 | div.style.boxSizing = "border-box";
164 | div.style.MozBoxSizing = "border-box";
165 | div.style.padding = "15px";
166 | div.style.background = "white";
167 | div.style.height = "100%";
168 | div.style.width = "350px";
169 | div.style.top = "0";
170 | div.style.right = "0";
171 | div.style.overflow = "scroll";
172 | div.style.overflowX = "hidden";
173 | div.style.display = "block";
174 |
175 | }
176 | })();
177 |
178 |
--------------------------------------------------------------------------------
/oabutton/static/public/js/add.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | function getLocation() {
4 | if (navigator.geolocation) {
5 | navigator.geolocation.getCurrentPosition(showPosition, denyAccess);
6 | }
7 | }
8 |
9 | function showPosition(position) {
10 | rounded_lat = Math.round(position.coords.latitude * 10) / 10;
11 | rounded_long = Math.round(position.coords.longitude * 10) / 10;
12 | $('#id_coords').val([rounded_lat, rounded_long]);
13 | $('#id_location').attr({'placeholder': 'Detected from browser', 'required': false, 'readonly': 'readonly'});
14 | }
15 |
16 | function denyAccess(error) {
17 | if (error.code == error.PERMISSION_DENIED)
18 | console.log("Geolocation denied");
19 | }
20 |
21 | getLocation();
22 |
23 | function pmc() {
24 | var doi = $('#id_doi').val();
25 |
26 | if (doi) {
27 | $.ajax({
28 | url: 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi',
29 | data: {
30 | db: "pmc",
31 | retmax: 1,
32 | term: doi + "[DOI]",
33 | tool: "oabutton"
34 | },
35 | dataType: "xml",
36 | success: function(response) {
37 | if (response.getElementsByTagName('Count')[0].textContent === '0') {
38 | return;
39 | }
40 |
41 | var pmcid = response.getElementsByTagName('Id')[0].textContent;
42 | var url = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" + pmcid + "/";
43 | $("#id_pmc").attr("href", url).show();
44 | }
45 | });
46 | }
47 | }
48 |
49 | pmc();
50 |
51 | function parseCrossRef(item) {
52 | var description = {};
53 |
54 | if (item.title) {
55 | description['Title'] = item.title;
56 | }
57 |
58 | if (item.author) {
59 | if (!$.isArray(item.author)) {
60 | item.author = [item.author];
61 | }
62 |
63 | var authors = [];
64 | $.each(item.author, function(index, author) {
65 | var name = [author.given, author.family];
66 | authors.push(name.join(" "));
67 | });
68 |
69 | description['Authors'] = authors.join(", ");
70 | }
71 |
72 | if (item["container-title"]) {
73 | description['Journal'] = item["container-title"];
74 | }
75 |
76 | if (item.issued && item.issued["date-parts"]) {
77 | // TODO: zero-pad or reformat the date, using Moment.js?
78 | description['Date'] = item.issued["date-parts"][0].join("-");
79 | }
80 |
81 | description = $.map(description, function(value, key) {
82 | return key + ": " + value;
83 | });
84 |
85 | return description.join("\n");
86 | }
87 |
88 | function lookup() {
89 | var doi = $('#id_doi').val();
90 |
91 | if (doi) {
92 | $.ajax({
93 | url: '/api/xref_proxy/' + encodeURIComponent(doi),
94 | dataType: "json",
95 | success: function(response) {
96 | if (response && response.URL) {
97 | $('#id_description').val(parseCrossRef(response));
98 | }
99 | }
100 | });
101 | }
102 | }
103 |
104 | lookup();
105 |
106 | // save details in localstorage
107 | function rememberDetails() {
108 | // test for localstorage support (from Modernizr)
109 | // fails if third-party data is not allowed (in an iframe)
110 | try {
111 | localStorage.setItem('test', 'test');
112 | localStorage.removeItem('test');
113 | } catch(e) {
114 | return;
115 | }
116 |
117 | var rememberMeInput = $('#id_remember'),
118 | rememberNodes = $('[data-remember]');
119 |
120 | var stored = localStorage.getItem('id_remember');
121 |
122 | // can't always store booleans in localstorage, so "false" (string) = "don't store"
123 | var remember = stored === null || stored === true || stored.toString() === 'true';
124 |
125 | if (remember) {
126 | rememberMeInput.prop('checked', true);
127 | }
128 |
129 | rememberMeInput.parent().show();
130 |
131 | // store/load details
132 | rememberNodes
133 | // save the details
134 | .on('change', function(){
135 | if (!remember) {
136 | return;
137 | }
138 |
139 | localStorage.setItem(this.getAttribute('id'), $(this).val());
140 | })
141 | // load the details
142 | .each(function() {
143 | $(this).val(localStorage.getItem(this.getAttribute('id')));
144 | });
145 |
146 | // when "remember me" is unchecked, delete stored details
147 | rememberMeInput.on('change', function() {
148 | remember = rememberMeInput.prop('checked');
149 | localStorage.setItem('id_remember', remember);
150 |
151 | if (remember) {
152 | // save the current values
153 | rememberNodes.trigger('change');
154 | } else {
155 | // remove the stored values
156 | rememberNodes.each(function() {
157 | localStorage.removeItem(this.getAttribute('id'));
158 | });
159 | }
160 | });
161 | }
162 |
163 | rememberDetails();
164 |
165 | function geocode(form) {
166 | return $.ajax({
167 | url: 'https://maps.googleapis.com/maps/api/geocode/json',
168 | data: {
169 | sensor: 'false',
170 | address: $('#id_location').val()
171 | },
172 | success: function(response) {
173 | if (response.results.length == 0) {
174 | alert("You location could not be identified, please try again!");
175 | } else {
176 | var location = response.results[0].geometry.location;
177 | $('#id_coords').val([location.lat, location.lng]);
178 | form.submit();
179 | }
180 | },
181 | error: function(jqXHR, textStatus, errorThrown) {
182 | console.log(jqXHR, textStatus, errorThrown);
183 | }
184 | });
185 | }
186 |
187 | function onSubmit(event) {
188 | var form = $(this);
189 |
190 | // Do geocoding only if needed
191 | if (!$('#id_coords').val()) {
192 | event.preventDefault();
193 | geocode(form);
194 | }
195 | }
196 |
197 | $('#id_accessed').val(new Date().toISOString());
198 | $('form').on("submit", onSubmit);
199 | });
200 |
--------------------------------------------------------------------------------
/oabutton/static/public/js/lib/jquery.color-2.1.2.min.js:
--------------------------------------------------------------------------------
1 | /*! jQuery Color v@2.1.2 http://github.com/jquery/jquery-color | jquery.org/license */
2 | (function(a,b){function m(a,b,c){var d=h[b.type]||{};return a==null?c||!b.def?null:b.def:(a=d.floor?~~a:parseFloat(a),isNaN(a)?b.def:d.mod?(a+d.mod)%d.mod:0>a?0:d.max")[0],k,l=a.each;j.style.cssText="background-color:rgba(1,1,1,.5)",i.rgba=j.style.backgroundColor.indexOf("rgba")>-1,l(g,function(a,b){b.cache="_"+a,b.props.alpha={idx:3,type:"percent",def:1}}),f.fn=a.extend(f.prototype,{parse:function(c,d,e,h){if(c===b)return this._rgba=[null,null,null,null],this;if(c.jquery||c.nodeType)c=a(c).css(d),d=b;var i=this,j=a.type(c),o=this._rgba=[];d!==b&&(c=[c,d,e,h],j="array");if(j==="string")return this.parse(n(c)||k._default);if(j==="array")return l(g.rgba.props,function(a,b){o[b.idx]=m(c[b.idx],b)}),this;if(j==="object")return c instanceof f?l(g,function(a,b){c[b.cache]&&(i[b.cache]=c[b.cache].slice())}):l(g,function(b,d){var e=d.cache;l(d.props,function(a,b){if(!i[e]&&d.to){if(a==="alpha"||c[a]==null)return;i[e]=d.to(i._rgba)}i[e][b.idx]=m(c[a],b,!0)}),i[e]&&a.inArray(null,i[e].slice(0,3))<0&&(i[e][3]=1,d.from&&(i._rgba=d.from(i[e])))}),this},is:function(a){var b=f(a),c=!0,d=this;return l(g,function(a,e){var f,g=b[e.cache];return g&&(f=d[e.cache]||e.to&&e.to(d._rgba)||[],l(e.props,function(a,b){if(g[b.idx]!=null)return c=g[b.idx]===f[b.idx],c})),c}),c},_space:function(){var a=[],b=this;return l(g,function(c,d){b[d.cache]&&a.push(c)}),a.pop()},transition:function(a,b){var c=f(a),d=c._space(),e=g[d],i=this.alpha()===0?f("transparent"):this,j=i[e.cache]||e.to(i._rgba),k=j.slice();return c=c[e.cache],l(e.props,function(a,d){var e=d.idx,f=j[e],g=c[e],i=h[d.type]||{};if(g===null)return;f===null?k[e]=g:(i.mod&&(g-f>i.mod/2?f+=i.mod:f-g>i.mod/2&&(f-=i.mod)),k[e]=m((g-f)*b+f,d))}),this[d](k)},blend:function(b){if(this._rgba[3]===1)return this;var c=this._rgba.slice(),d=c.pop(),e=f(b)._rgba;return f(a.map(c,function(a,b){return(1-d)*e[b]+d*a}))},toRgbaString:function(){var b="rgba(",c=a.map(this._rgba,function(a,b){return a==null?b>2?1:0:a});return c[3]===1&&(c.pop(),b="rgb("),b+c.join()+")"},toHslaString:function(){var b="hsla(",c=a.map(this.hsla(),function(a,b){return a==null&&(a=b>2?1:0),b&&b<3&&(a=Math.round(a*100)+"%"),a});return c[3]===1&&(c.pop(),b="hsl("),b+c.join()+")"},toHexString:function(b){var c=this._rgba.slice(),d=c.pop();return b&&c.push(~~(d*255)),"#"+a.map(c,function(a){return a=(a||0).toString(16),a.length===1?"0"+a:a}).join("")},toString:function(){return this._rgba[3]===0?"transparent":this.toRgbaString()}}),f.fn.parse.prototype=f.fn,g.hsla.to=function(a){if(a[0]==null||a[1]==null||a[2]==null)return[null,null,null,a[3]];var b=a[0]/255,c=a[1]/255,d=a[2]/255,e=a[3],f=Math.max(b,c,d),g=Math.min(b,c,d),h=f-g,i=f+g,j=i*.5,k,l;return g===f?k=0:b===f?k=60*(c-d)/h+360:c===f?k=60*(d-b)/h+120:k=60*(b-c)/h+240,h===0?l=0:j<=.5?l=h/i:l=h/(2-i),[Math.round(k)%360,l,j,e==null?1:e]},g.hsla.from=function(a){if(a[0]==null||a[1]==null||a[2]==null)return[null,null,null,a[3]];var b=a[0]/360,c=a[1],d=a[2],e=a[3],f=d<=.5?d*(1+c):d+c-d*c,g=2*d-f;return[Math.round(o(g,f,b+1/3)*255),Math.round(o(g,f,b)*255),Math.round(o(g,f,b-1/3)*255),e]},l(g,function(c,e){var g=e.props,h=e.cache,i=e.to,j=e.from;f.fn[c]=function(c){i&&!this[h]&&(this[h]=i(this._rgba));if(c===b)return this[h].slice();var d,e=a.type(c),k=e==="array"||e==="object"?c:arguments,n=this[h].slice();return l(g,function(a,b){var c=k[e==="object"?a:b.idx];c==null&&(c=n[b.idx]),n[b.idx]=m(c,b)}),j?(d=f(j(n)),d[h]=n,d):f(n)},l(g,function(b,e){if(f.fn[b])return;f.fn[b]=function(f){var g=a.type(f),h=b==="alpha"?this._hsla?"hsla":"rgba":c,i=this[h](),j=i[e.idx],k;return g==="undefined"?j:(g==="function"&&(f=f.call(this,j),g=a.type(f)),f==null&&e.empty?this:(g==="string"&&(k=d.exec(f),k&&(f=j+parseFloat(k[2])*(k[1]==="+"?1:-1))),i[e.idx]=f,this[h](i)))}})}),f.hook=function(b){var c=b.split(" ");l(c,function(b,c){a.cssHooks[c]={set:function(b,d){var e,g,h="";if(d!=="transparent"&&(a.type(d)!=="string"||(e=n(d)))){d=f(e||d);if(!i.rgba&&d._rgba[3]!==1){g=c==="backgroundColor"?b.parentNode:b;while((h===""||h==="transparent")&&g&&g.style)try{h=a.css(g,"backgroundColor"),g=g.parentNode}catch(j){}d=d.blend(h&&h!=="transparent"?h:"_default")}d=d.toRgbaString()}try{b.style[c]=d}catch(j){}}},a.fx.step[c]=function(b){b.colorInit||(b.start=f(b.elem,c),b.end=f(b.end),b.colorInit=!0),a.cssHooks[c].set(b.elem,b.start.transition(b.end,b.pos))}})},f.hook(c),a.cssHooks.borderColor={expand:function(a){var b={};return l(["Top","Right","Bottom","Left"],function(c,d){b["border"+d+"Color"]=a}),b}},k=a.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}})(jQuery);
--------------------------------------------------------------------------------
/oabutton/static/public/js/index.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 |
3 | var oabutton = {
4 | renderMap : function () {
5 | if (typeof L == 'undefined') return;
6 |
7 | var map = L.map('map', {
8 | center: [20, 0],
9 | maxZoom: 18,
10 | minZoom: 2,
11 | scrollWheelZoom: false,
12 | touchZoom: false,
13 | zoom: 2
14 | });
15 | L.tileLayer('http://{s}.tile.cloudmade.com/cee9bfb83d854a2f89a4a2445aa9f595/997/256/{z}/{x}/{y}.png', {
16 | attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA , Imagery © CloudMade '
17 | }).addTo(map);
18 |
19 | var oaIcon = L.icon({
20 | iconUrl: 'static/img/noalogo.png',
21 | iconSize: [12, 19],
22 | iconAnchor: [6, 9],
23 | popupAnchor: [0, -12]
24 | });
25 |
26 | var markers = new L.MarkerClusterGroup();
27 | for (var i = 0; i < events.length; i++) {
28 | var evt = events[i];
29 | if(evt.coords.lat && evt.coords.lng) {
30 | bubble_content = '' + evt.user_name;
31 | if (evt.user_profession != '') {
32 | bubble_content += ' (' + evt.user_profession + ') ';
33 | }
34 | bubble_content += ' ';
35 | bubble_content += '' + evt.story + '
';
36 | bubble_content += 'doi ';
37 | bubble_content += ' | ';
38 | bubble_content += 'url ';
39 | bubble_content += ' | ';
40 | bubble_content += evt.accessed || '';
41 |
42 | var marker = new L.marker([evt.coords.lat, evt.coords.lng], { title: bubble_content, icon: oaIcon });
43 | marker.bindPopup(bubble_content);
44 |
45 | markers.addLayer(marker);
46 | }
47 | }
48 | map.addLayer(markers);
49 | }
50 | }
51 |
52 | // Highlight some node. This ought to be moved to some common JS
53 | $.fn.animateHighlight = function(highlightColor, duration) {
54 | var highlightBg = highlightColor || "#FFFF9C";
55 | var animateMs = duration || 1500;
56 | var originalBg = this.css("backgroundColor");
57 | this.stop().css("background-color",
58 | highlightBg).animate({backgroundColor:
59 | originalBg}, animateMs);
60 | };
61 |
62 | // Bind submission form
63 | $('#form-bookmarklet').ajaxForm({
64 | target: '#divToUpdate',
65 | dataType: 'json',
66 | url: '/api/signin/',
67 | error: function(ctx) {
68 | var errors = JSON.parse(ctx.responseText).errors;
69 |
70 | if ('email' in errors) {
71 | $('#id_email').animateHighlight("#dd0000", 1000);
72 | }
73 |
74 | if ('name' in errors) {
75 | $('#id_name').animateHighlight("#dd0000", 1000);
76 | }
77 |
78 | if ('confirm_public' in errors) {
79 | $('label.confirm-label').animateHighlight("#dd0000", 1000);
80 | }
81 | },
82 | success: function(responseJSON, statusText, xhr, formElem) {
83 |
84 | // Set URL from service response
85 | var bookmarklet = $('#bookmarklet .content');
86 | $('.btn-primary', bookmarklet).attr('href',
87 | "javascript:document.getElementsByTagName('body')[0]" +
88 | ".appendChild(document.createElement('script'))" +
89 | ".setAttribute('src','"+responseJSON['url']+"');"
90 | );
91 |
92 | // Show the new bookmarklet and instructions, roll up form
93 | $('#bookmarklet').show();
94 | $('#form-bookmarklet').slideUp();
95 |
96 | window.location = '#top';
97 | $('#help-bookmarklet').fadeIn();
98 |
99 | } // -success
100 | }); // -ajaxForm
101 |
102 | // Scrollspy effects (unused)
103 | //$('body').on('activate.bs.scrollspy', function (e) {
104 | //console.log(e);
105 | //});
106 |
107 | // Show the map underlay (later as effect)
108 | $('#map .underlay').fadeIn();
109 |
110 | // Stop video on close dialog
111 | $('#video-modal').on('hidden.bs.modal', function () {
112 | $('iframe').each(function() {
113 | this.contentWindow.postMessage(
114 | '{"event":"command","func":"pauseVideo","args":""}', '*'
115 | );
116 | });
117 | });
118 |
119 | // Use JQuery Placeholder plugin on older browsers (ex. IE 9)
120 | $('#form-bookmarklet input[type="text"]').placeholder();
121 |
122 | // Position the thumbnail hovers
123 | var midpoint = $('.thumbnails').width() / 2;
124 | $('.thumbnails li').each(function() {
125 | if ($(this).position().left >= midpoint) {
126 | $(this).addClass("right");
127 | }
128 | });
129 |
130 | // Tap as hover on touchscreens
131 | $('.thumbnails a.thumb').bind('touchstart', function(e){
132 | $(this).parent().addClass('hover');
133 | e.stopPropagation();
134 | }).bind('touchend', function(e){
135 | $(this).parent().parent().find('.hover').removeClass('hover');
136 | e.stopPropagation();
137 | }).css('visibility', 'visible'); // Avoids doubles while loading JS
138 | oabutton.renderMap();
139 |
140 | // Page links should all be new window
141 | $('a[href^="http"]').attr('target', '_blank');
142 | });
143 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/tests.py:
--------------------------------------------------------------------------------
1 | """
2 | This file demonstrates writing tests using the unittest module. These will pass
3 | when you run "manage.py test".
4 |
5 | Replace this with more appropriate tests for your application.
6 | """
7 |
8 | from django.test import TestCase
9 | from django.test.client import Client
10 | from nose.tools import eq_, ok_
11 | from oabutton.apps.bookmarklet.models import Event, User
12 | import datetime
13 | import json
14 | import re
15 |
16 |
17 | class APITest(TestCase):
18 | def setUp(self):
19 | """
20 | verify that the JSON emitted is compatible with the javascript
21 | map stuff
22 | """
23 | # check that we have all the signin fields
24 | self.EMAIL = 'new_email@foo.com'
25 | self.POST_DATA = {u'email': self.EMAIL,
26 | 'name': 'some name',
27 | 'profession': 'Student',
28 | 'confirm_public': 'checked',
29 | 'mailinglist': 'checked'}
30 |
31 | for user in User.objects.filter(username=self.EMAIL):
32 | user.delete()
33 |
34 | c = Client()
35 | response = c.post('/api/signin/', self.POST_DATA)
36 |
37 | eq_(response.status_code, 200)
38 | self.user = User.objects.get(username=self.EMAIL)
39 |
40 | eq_(self.user.name, 'some name')
41 | eq_(self.user.email, self.EMAIL)
42 | eq_(self.user.profession, 'Student')
43 | ok_(self.user.mailinglist)
44 |
45 | def test_add_post(self):
46 | '''
47 | We need to make sure all fields of the Event object are
48 | serialized back to MongoDB
49 | '''
50 | POST_DATA = {u'story': [u'some access requirement'],
51 | u'doi': [u'10.1016/j.urology.2010.05.009.'],
52 | u'url': [u'http://www.ncbi.nlm.nih.gov/pubmed/20709373'],
53 | u'coords': [u'44,-79.5'],
54 | u'location': [u'Somewhere'],
55 | u'accessed': [u'Mon, 09 Sep 2013 14:54:42 GMT'],
56 | u'description': [u'some description'],
57 | u'user_id': self.user.id, }
58 |
59 | c = Client()
60 | response = c.post('/api/post/', POST_DATA)
61 |
62 | assert response.status_code == 302
63 |
64 | evt = Event.objects.get(id=c.session['data']['event_id'])
65 |
66 | expected = {'doi': u'10.1016/j.urology.2010.05.009.',
67 | 'url': u'http://www.ncbi.nlm.nih.gov/pubmed/20709373',
68 | 'coords': {u'lat': 44.0, u'lng': -79.5},
69 | 'location': 'Somewhere',
70 | 'accessed': datetime.datetime(2013, 9, 9, 14, 54, 42),
71 | 'email': None}
72 | for k, v in expected.items():
73 | assert getattr(evt, k) == v
74 |
75 | def test_event_json(self):
76 | """
77 | verify that the JSON emitted is compatible with the javascript
78 | map stuff
79 | """
80 | user = self.user
81 |
82 | POST_DATA = {u'story': [u'some access requirement'],
83 | u'doi': [u'10.1016/j.urology.2010.05.009.'],
84 | u'url': [u'http://www.ncbi.nlm.nih.gov/pubmed/20709373'],
85 | u'coords': [u'44,-79.5'],
86 | u'location': [u''],
87 | u'accessed': [u'Mon, 09 Sep 2013 14:54:42 GMT'],
88 | u'description': [u'some description'],
89 | u'user_id': user.id}
90 |
91 | c = Client()
92 | response = c.post('/api/post/', POST_DATA)
93 |
94 | assert response.status_code == 302
95 |
96 | json_data = Event.objects.filter(id=c.session['data']['event_id']).to_json()
97 | jdata = json.loads(json_data)
98 | eq_(len(jdata), 1)
99 | data = jdata[0]
100 | eq_(data['coords'], {'lat': 44.0, 'lng': -79.5})
101 | eq_(data['doi'], '10.1016/j.urology.2010.05.009.')
102 | eq_(data['url'], 'http://www.ncbi.nlm.nih.gov/pubmed/20709373')
103 |
104 | actual_date = datetime.datetime.fromtimestamp(data['accessed']['$date'] / 1000)
105 | eq_(actual_date.year, 2013)
106 | eq_(actual_date.month, 9)
107 | eq_(actual_date.day, 9)
108 |
109 | eq_(data['user_name'], 'some name')
110 | eq_(data['user_profession'], 'Student')
111 | eq_(data['story'], 'some access requirement')
112 |
113 | # Check that we can resolve the original user oid
114 | evt = Event.objects.filter(id=c.session['data']['event_id'])[0]
115 | assert evt.user_id is not None
116 |
117 | def test_update_signon(self):
118 | """
119 | verify that the JSON emitted is compatible with the javascript
120 | map stuff
121 | """
122 | user = self.user
123 |
124 | c = Client()
125 | response = c.post('/api/signin/', self.POST_DATA)
126 |
127 | eq_(response.status_code, 200)
128 | eq_({'url': user.get_bookmarklet_url()}, json.loads(response.content))
129 |
130 | # check that we have all the signin fields
131 | user = User.objects.filter(username=self.EMAIL)[0]
132 | eq_(user.name, 'some name')
133 | eq_(user.email, self.EMAIL)
134 | eq_(user.profession, 'Student')
135 | ok_(user.mailinglist)
136 |
137 | def test_search_doi_after_post(self):
138 | '''
139 | Tests to make sure the response to submitting the form is rendered
140 | correctly.
141 | '''
142 | POST_DATA = {'name': 'mock name',
143 | 'profession': 'mock profession',
144 | 'location': 'mock location',
145 | 'coords': '33.2,21.9',
146 | 'accessed': 'Mon, 09 Sep 2013 14:54:42 GMT',
147 | 'doi': 'some.doi',
148 | 'url': 'http://some.url/some_path',
149 | 'story': 'some_story',
150 | 'email': 'foo@blah.com',
151 | 'user_id': self.user.id,
152 | }
153 |
154 | c = Client()
155 | response = c.post('/api/post/', POST_DATA)
156 |
157 | response = c.post('/api/form/page3/')
158 | # Check that the DOI is passed through correctly
159 | data_doi_re = re.compile(']*data-doi="%s">'
160 | % POST_DATA['doi'])
161 | assert data_doi_re.search(response.content) is not None
162 |
163 | def test_data_xref_proxy(self):
164 | # TODO: Need a proper test for this that doesn't clobber the
165 | # network. Inject a fake requests mock object into xref_proxy
166 | # prior to execution
167 | pass
168 | """
169 | c = Client()
170 | response = c.get('/api/xref_proxy/10.1103/PhysRevD.15.2752')
171 | assert json.loads(response.content) != None
172 | """
173 |
--------------------------------------------------------------------------------
/oabutton/static/public/js/lib/bootstrap-dialog.js:
--------------------------------------------------------------------------------
1 | /* ================================================
2 | * Make use of Twitter Bootstrap's modal more monkey-friendly
3 | * Licensed under The MIT License.
4 | * ================================================ */
5 | var BootstrapDialog = null;
6 | !function($){
7 | "use strict";
8 |
9 | BootstrapDialog = function(options){
10 | this.defaultOptions = {
11 | 'title' : null,
12 | 'content' : null,
13 | 'draggableHandles' : '',
14 | 'autoDestroy' : true,
15 | 'buttons' : [],
16 | 'ready' : null,
17 | // Bootstrap's options
18 | 'backdrop' : 'static'
19 | };
20 | this.dataHolder = {};
21 | this.buttons = {};
22 | this.init(options);
23 | };
24 |
25 | BootstrapDialog.prototype = {
26 | constructor: BootstrapDialog,
27 | init: function(options){
28 | this.options = $.extend(this.defaultOptions, options, true);
29 | },
30 | initDialog: function(){
31 | this.setDialog(this.createDialog());
32 | this.setHeader(this.createHeader());
33 | this.setBody(this.createBody());
34 | this.setFooter(this.createFooter());
35 | this.getDialog().append(this.getHeader()).append(this.getBody()).append(this.getFooter());
36 | if (this.options.autoDestroy) {
37 | this.getDialog().on('hidden', function(event){
38 | $(this).remove();
39 | });
40 | }
41 | },
42 | initDraggable: function(){
43 | var handles = this.options.draggableHandles.split(',');
44 | var handlesArray = [];
45 | for(var i=0; i 0) {
52 | this.getDialog().draggable({
53 | handle: handlesArray.join(',')
54 | });
55 | }
56 | },
57 | initButtons: function(){
58 | var $footer = this.getFooter();
59 | var btns = this.getButtons();
60 | for(var i=0; iButton');
63 | if (btn.id){
64 | this.buttons[btn.id] = $btn;
65 | }
66 | if (btn.label) {
67 | $btn.text(btn.label);
68 | }
69 | if (btn.cssClass) {
70 | $btn.addClass(btn.cssClass);
71 | }
72 | $btn.click({btn: btn, $btn: $btn, dialog: this}, function(event){
73 | if(event.data.btn.onclick){
74 | event.data.btn.onclick.call(event.target, event.data.dialog);
75 | }
76 | });
77 | $footer.append($btn);
78 | }
79 | },
80 | open: function(){
81 | this.initDialog();
82 | this.initDraggable();
83 | this.initButtons();
84 | this.ready();
85 | this.getDialog().modal('show');
86 |
87 | return this;
88 | },
89 | close: function(){
90 | this.getDialog().modal('hide');
91 | },
92 | destroy: function(){
93 | this.getDialog().remove();
94 | },
95 | createDialog: function(){
96 | var $dialog = $(document.createElement('div'));
97 | $dialog.addClass('modal fade hide');
98 | $('body').append($dialog);
99 | $dialog.modal({
100 | backdrop : this.options.backdrop,
101 | show : false
102 | });
103 |
104 | return $dialog;
105 | },
106 | setDialog: function($dialog){
107 | this.$dialog = $dialog;
108 |
109 | return this;
110 | },
111 | getDialog: function(){
112 | return this.$dialog;
113 | },
114 | createHeader: function(){
115 | var $header = $('');
116 | if (this.getTitle() == null) {
117 | $header.hide();
118 | }else{
119 | $header.append(this.createDynamicContent(this.getTitle()));
120 | }
121 |
122 | return $header;
123 | },
124 | setHeader: function($header){
125 | this.$header = $header;
126 |
127 | return this;
128 | },
129 | getHeader: function(){
130 | return this.$header;
131 | },
132 | createBody: function(){
133 | var $body = $('
');
134 | if (this.getContent() != null) {
135 | $body.append(this.createDynamicContent(this.getContent()));
136 | }
137 |
138 | return $body;
139 | },
140 | setBody: function($body){
141 | this.$body = $body;
142 |
143 | return this;
144 | },
145 | getBody: function(){
146 | return this.$body;
147 | },
148 | createFooter: function(){
149 | return $('');
150 | },
151 | setFooter: function($footer){
152 | this.$footer = $footer;
153 |
154 | return this;
155 | },
156 | getFooter: function(){
157 | return this.$footer;
158 | },
159 | setButton: function(id, $btn){
160 | this.buttons[id] = $btn;
161 |
162 | return this;
163 | },
164 | getButton: function(id){
165 | return this.buttons[id];
166 | },
167 | createDynamicContent: function(rawContent){
168 | var contentType = typeof rawContent;
169 | if (contentType != 'function') {
170 | return rawContent;
171 | }
172 |
173 | return rawContent(this);
174 | },
175 | setData: function(key, value){
176 | this.dataHolder[key] = value;
177 |
178 | return this;
179 | },
180 | getData: function(key){
181 | return this.dataHolder[key];
182 | },
183 | setTitle: function(title){
184 | this.options.title = title;
185 |
186 | return this;
187 | },
188 | getTitle: function(){
189 | return this.options.title;
190 | },
191 | setContent: function(content){
192 | this.options.content = content;
193 |
194 | return this;
195 | },
196 | getContent: function(){
197 | return this.options.content;
198 | },
199 | setButtons: function(buttons){
200 | this.options.buttons = buttons;
201 |
202 | return this;
203 | },
204 | getButtons: function(){
205 | return this.options.buttons;
206 | },
207 | setReady: function(readyCallback){
208 | this.options.ready = readyCallback;
209 |
210 | return this;
211 | },
212 | getReady: function(){
213 | return this.options.ready;
214 | },
215 | /**
216 | * Run this after the dialog is ready
217 | */
218 | ready: function(){
219 | if (typeof this.options.ready == 'function') {
220 | this.options.ready(this);
221 | }
222 |
223 | return this;
224 | }
225 | };
226 |
227 | /* ================================================
228 | * For lazy people
229 | * ================================================ */
230 | BootstrapDialog.alert = function(message, callback){
231 | new BootstrapDialog({
232 | content: message,
233 | buttons: [{
234 | label : 'OK',
235 | cssClass: 'btn-primary',
236 | onclick : function(dialog){
237 | if (typeof callback == 'function') {
238 | callback();
239 | }
240 | dialog.close();
241 | }
242 | }]
243 | }).open();
244 | };
245 |
246 | BootstrapDialog.confirm = function(message, callback){
247 | new BootstrapDialog({
248 | content: message,
249 | buttons: [{
250 | label : 'Cancel',
251 | onclick : function(dialog){
252 | if (typeof callback == 'function') {
253 | callback(false);
254 | }
255 | dialog.close();
256 | }
257 | }, {
258 | label : 'OK',
259 | cssClass: 'btn-primary',
260 | onclick : function(dialog){
261 | if (typeof callback == 'function') {
262 | callback(true);
263 | }
264 | dialog.close();
265 | }
266 | }]
267 | }).open();
268 | };
269 |
270 | }(window.jQuery);
271 |
--------------------------------------------------------------------------------
/oabutton/apps/bookmarklet/views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from django.core import serializers
3 | from django.core.context_processors import csrf
4 | from django.http import HttpResponse, HttpResponseServerError
5 | from django.shortcuts import redirect
6 | from django.shortcuts import render_to_response
7 | from django.views.decorators.csrf import csrf_protect
8 | from models import Event
9 | from oabutton.apps.bookmarklet.models import User
10 | from oabutton.common import SigninForm, Bookmarklet
11 | import dateutil
12 | import json
13 | import requests
14 |
15 |
16 | def show_map(req):
17 | # TODO: we need to make this smarter. Coallescing the lat/long
18 | # data on a nightly basis and folding that down into clustered
19 | # points would mean we throw less data down to the browser
20 | json_data = Event.objects.all().to_json()
21 | count = Event.objects.count()
22 | context = {'title': 'Map', 'events': json_data, 'count': count}
23 | return render_to_response(req, 'bookmarklet/site/map.html', context)
24 |
25 |
26 | def get_json(req):
27 | # Dump all data as JSON. This seems like a terrible idea when the
28 | # dataset gets large.
29 | json_data = serializers.serialize("json", Event.objects.all())
30 | return HttpResponse(json_data, content_type="application/json")
31 |
32 |
33 | @csrf_protect
34 | def signin(request):
35 | """
36 | One time signin to create a bookmarklet using HTTP POST.
37 |
38 | The only required field is the email address
39 |
40 | Create a new user and return the URL to the user bookmarklet
41 | """
42 | if request.method == 'POST':
43 | # If the form has been submitted...
44 | form = SigninForm(request.POST) # A form bound to the POST data
45 | if form.is_valid(): # All validation rules pass
46 | # TODO: do stuff here
47 | manager = get_user_model()._default_manager
48 | data = dict(form.cleaned_data)
49 | data['username'] = data['email']
50 |
51 | try:
52 | user = User.objects.get(username=data['email'])
53 | user.mailinglist = data['mailinglist']
54 | user.name = data['name']
55 | user.profession = data['profession']
56 | user.usernmae = data['username']
57 | user.save()
58 | except User.DoesNotExist:
59 | # Default the username to be email address
60 | user = manager.create_user(**data)
61 |
62 | return HttpResponse(json.dumps({'url': user.get_bookmarklet_url()}), content_type="application/json")
63 | return HttpResponseServerError(json.dumps({'errors': form._errors}), content_type="application/json")
64 |
65 |
66 | #def form(req, user_id):
67 | # """
68 | # Show the bookmarklet form
69 | # """
70 | # form = Bookmarklet(req.GET)
71 | #
72 | # if 'doi' in form.data:
73 | # form.fields['doi'].widget.attrs['readonly'] = 'readonly'
74 | # form.fields['doi'].widget.attrs['value'] = form.data['doi']
75 | #
76 | # if 'url' in form.data:
77 | # form.fields['url'].widget.attrs['value'] = form.data['url']
78 | #
79 | # form.fields['user_id'].widget.attrs['value'] = user_id
80 | #
81 | # c = {}
82 | # c.update(csrf(req))
83 | # c.update({'bookmarklet': form, 'user_id': user_id})
84 | # return render_to_response('bookmarklet/index.html', c)
85 | #
86 |
87 | def form1(req, user_id):
88 | """
89 | Show the bookmarklet form
90 | """
91 | form = Bookmarklet(req.GET)
92 |
93 | if 'doi' in form.data:
94 | form.fields['doi'].widget.attrs['readonly'] = 'readonly'
95 | form.fields['doi'].widget.attrs['value'] = form.data['doi']
96 |
97 | if 'url' in form.data:
98 | form.fields['url'].widget.attrs['value'] = form.data['url']
99 |
100 | form.fields['user_id'].widget.attrs['value'] = user_id
101 |
102 | c = {}
103 | req.session['user_id'] = user_id
104 |
105 | c.update(csrf(req))
106 | c.update({'bookmarklet': form, 'user_id': user_id})
107 | return render_to_response('bookmarklet/page1.html', c)
108 |
109 |
110 | def form2(req):
111 | """
112 | Show the bookmarklet form. We just need the CSRF token here.
113 | """
114 | data = req.session['data']
115 | scholar_url = data['scholar_url']
116 | doi = data['doi']
117 | event = Event.objects.get(id=data['event_id'])
118 |
119 | c = {}
120 | c.update(csrf(req))
121 | c.update({'scholar_url': scholar_url, 'doi': doi, 'url': event.url})
122 | return render_to_response('bookmarklet/page2.html', c)
123 |
124 |
125 | def form3(req):
126 | """
127 | Show the bookmarklet form
128 | """
129 |
130 | if req.method != 'POST':
131 | return redirect('bookmarklet:form1', user_id=req.session['user_id'])
132 |
133 | data = req.session['data']
134 | scholar_url = data['scholar_url']
135 | doi = data['doi']
136 | event = Event.objects.get(id=data['event_id'])
137 |
138 | c = {}
139 | c.update(csrf(req))
140 | c.update({'scholar_url': scholar_url, 'doi': doi, 'url': event.url})
141 | return render_to_response('bookmarklet/page3.html', c)
142 |
143 |
144 | def add_post(req):
145 | c = {}
146 | c.update(csrf(req))
147 |
148 | if req.method == 'POST':
149 | # If the form has been submitted...
150 | form = Bookmarklet(req.POST) # A form bound to the POST data
151 | if form.is_valid(): # All validation rules pass
152 | evt_dict = dict(form.cleaned_data)
153 | lat, lng = evt_dict['coords'].split(',')
154 | evt_dict['coords'] = {'lat': float(lat), 'lng': float(lng)}
155 | if evt_dict['accessed'] != '':
156 | evt_dict['accessed'] = dateutil.parser.parse(evt_dict['accessed'])
157 |
158 | user = User.objects.get(id=evt_dict['user_id'])
159 | evt_dict['user_name'] = user.name
160 | evt_dict['user_profession'] = user.profession
161 |
162 | event = Event(**evt_dict)
163 | event.save()
164 |
165 | scholar_url = ''
166 | if 'doi' in evt_dict:
167 | # Some dumb DOIs end with '.' characters
168 | while evt_dict['doi'].endswith('.'):
169 | evt_dict['doi'] = evt_dict['doi'][:-1]
170 | doi = evt_dict['doi']
171 | scholar_url = 'http://scholar.google.com/scholar?cluster=http://dx.doi.org/%s' % doi
172 |
173 | req.session['data'] = {'event_id': event.id,
174 | 'scholar_url': scholar_url,
175 | 'doi': doi}
176 |
177 | return redirect('bookmarklet:form2')
178 | else:
179 | return redirect('bookmarklet:form1', user_id=req.session['user_id'])
180 |
181 |
182 | def xref_proxy(req, doi):
183 | url = "http://data.crossref.org/%s" % doi
184 | headers = {'Accept': "application/vnd.citationstyles.csl+json"}
185 | r = requests.get(url, headers=headers)
186 | return HttpResponse(r.text, content_type="application/json")
187 |
188 |
189 | def generate_bookmarklet(req, user_id):
190 | return render_to_response('bookmarklet/bookmarklet.html',
191 | {'user_id': user_id},
192 | content_type="application/javascript")
193 |
--------------------------------------------------------------------------------
/oabutton/static/test/test.js:
--------------------------------------------------------------------------------
1 | module("success.js", {
2 | setup: function() {
3 | this.doi = "10.1038/nrrheum.2013.47";
4 | this.metadata = {
5 | doi: this.doi,
6 | title: "Acute inflammatory arthritis: Monoarthritis risk stratification in Lyme disease",
7 | authors: "Robert T. Schoen",
8 | publication: "Nature Reviews Rheumatology",
9 | date: "2013-4-9",
10 | };
11 | },
12 | });
13 |
14 | test( "parseCrossRef", function() {
15 | var entry = {"title":"Acute inflammatory arthritis: Monoarthritis risk stratification in Lyme disease","link":{"href":"http://dx.doi.org/10.1038%2Fnrrheum.2013.47"},"id":"http://dx.doi.org/10.1038/nrrheum.2013.47","updated":"2013-09-23T06:07:17-04:00","content":{"div":{"p":[{"b":"Acute inflammatory arthritis: Monoarthritis risk stratification in Lyme disease"},"\n\tNature Reviews Rheumatology. \n\t10.1038/nrrheum.2013.47","\n\tAuthors:\n\t\n\t\n\tRobert T. Schoen\n\t\n\t\n\t\n "],"xmlns":"http://www.w3.org/1999/xhtml"},"type":"xhtml"},"pam:message":{"pam:article":{"xhtml:head":{"xmlns:xhtml":"http://www.w3.org/1999/xhtml"},"dc:identifier":"10.1038/nrrheum.2013.47","dc:title":"Acute inflammatory arthritis: Monoarthritis risk stratification in Lyme disease","dc:publisher":"Nature Publishing Group","dc:isPartOf":"1759-4790","prism:alternateTitle":"Nature Reviews Rheumatology","dc:creator":"Robert T. Schoen","prism:publicationName":"Nature Reviews Rheumatology","prism:issn":"1759-4790","prism:eIssn":"1759-4804","prism:doi":"10.1038/nrrheum.2013.47","prism:publicationDate":"2013-4-9","prism:volume":"9","prism:startingPage":"261","prism:endingPage":"262","prism:url":"http://dx.doi.org/10.1038%2Fnrrheum.2013.47"},"xmlns:pam":"http://prismstandard.org/namespaces/pam/2.0/","xsi:schemaLocation":"http://prismstandard.org/namespaces/pam/2.0/ \n\t\t\t\t http://www.prismstandard.org/schemas/pam/2.1/pam.xsd"}};
16 |
17 | var result = oabSuccess.parseCrossRef(entry, this.doi);
18 |
19 | deepEqual(result, this.metadata, "Parses data correctly");
20 | });
21 |
22 | test( "addScholarDOILink", function() {
23 | var $fixture = $('#qunit-fixture');
24 | $fixture.append('');
25 |
26 | oabSuccess.addScholarDOILink(this.metadata);
27 |
28 | var link = $("a", $fixture);
29 | equal(link.length, 1, "Only one link added");
30 | ok(link.attr('href').indexOf('scholar.google.com') > -1, "Link goes to Google Scholar");
31 | ok(link.attr('href').indexOf(encodeURIComponent(this.metadata.doi)) > -1, "Link href contains the DOI");
32 | });
33 |
34 | test( "addScholarTitleLink", function() {
35 | var $fixture = $('#qunit-fixture');
36 | $fixture.append('');
37 |
38 | oabSuccess.addScholarTitleLink(this.metadata);
39 |
40 | var link = $("a", $fixture);
41 | equal(link.length, 1, "Only one link added");
42 | ok(link.attr('href').indexOf('scholar.google.com') > -1, "Link goes to Google Scholar");
43 | ok(link.attr('href').indexOf(encodeURIComponent(this.metadata.title)) > -1, "Link href contains the DOI");
44 | });
45 |
46 | asyncTest( "discoverCORELinks", function() {
47 | expect(3);
48 |
49 | var $fixture = $('#qunit-fixture');
50 | $fixture.append('');
51 |
52 | $.mockjax({
53 | url: "/metadata/coresearch.json/*",
54 | responseText: {"ListRecords":[{"total_hits":5015},{"record":{"header":{"header:content":{"core:repositoryIdentifier":"143","identifier":"669636"},"header:attr":{"xmlns:core":"http:\/\/core.kmi.open.ac.uk\/api\/doc"}},"metadata":{"oai_dc:dc":{"oai_dc:ns":[{"xmlns:oai_dc":"http:\/\/www.openarchives.org\/OAI\/2.0\/oai_dc\/","xmlns:dc":"http:\/\/purl.org\/dc\/elements\/1.1\/"}],"dc:creator":"R Kudyar","dc:format":"application\/pdf","dc:source":"http:\/\/www.jkscience.org\/archive\/111\/18-RL-JACORD%20ARTHRITIS.pdf","dc:date":"2009","dc:identifier":"http:\/\/www.jkscience.org\/archive\/111\/18-RL-JACORD%20ARTHRITIS.pdf","dc:description":"A case of a patient with rheumatic valvulardisease who had comparable deformities of the handsand fingers and who fulfilled all of the criteriasuggested by Bywaters to describe Jaccoud's Arthritis is decribed here.","dc:title":"Jaccoud\u2019s Arthritis"}}}},{"record":{"header":{"header:content":{"core:repositoryIdentifier":"140","identifier":"60225"},"header:attr":{"xmlns:core":"http:\/\/core.kmi.open.ac.uk\/api\/doc"}},"metadata":{"oai_dc:dc":{"oai_dc:ns":[{"xmlns:oai_dc":"http:\/\/www.openarchives.org\/OAI\/2.0\/oai_dc\/","xmlns:dc":"http:\/\/purl.org\/dc\/elements\/1.1\/"}],"dc:creator":"Zai Liu, Guo Deng, Simon Foster and Andrej Tarkowski","dc:format":"application\/pdf","dc:source":"http:\/\/eprints.whiterose.ac.uk\/21\/1\/ar330.pdf","dc:date":"2001-09-17","dc:identifier":"http:\/\/eprints.whiterose.ac.uk\/21\/1\/ar330.pdf","dc:description":"Staphylococcus aureus is one of the most important pathogens in septic arthritis. To analyse the arthritogenic properties of staphylococcal peptidoglycan (PGN), highly purified PGN from S. aureus was intra-articularly injected into murine joints. The results demonstrate that PGN will trigger arthritis in a dose-dependent manner. A single injection of this compound leads to massive infiltration of predominantly macrophages and polymorphonuclear cells with occasional signs of cartilage and\/or bone destruction, lasting for at least 14 days. Further studies showed that this condition is mediated by the combined impact of acquired and innate immune systems. Our results indicate that PGN exerts a central role in joint inflammation triggered by S. aureus.","dc:title":"Staphylococcal peptidoglycans induce arthritis"}}}},{"record":{"header":{"header:content":{"core:repositoryIdentifier":"143","identifier":"5726004"},"header:attr":{"xmlns:core":"http:\/\/core.kmi.open.ac.uk\/api\/doc"}},"metadata":{"oai_dc:dc":{"oai_dc:ns":[{"xmlns:oai_dc":"http:\/\/www.openarchives.org\/OAI\/2.0\/oai_dc\/","xmlns:dc":"http:\/\/purl.org\/dc\/elements\/1.1\/"}],"dc:creator":"Karambin Mohammad Mehdi and Hashemian Hooman","dc:format":"application\/pdf","dc:source":"http:\/\/journals.tums.ac.ir\/PdfMed.aspx?pdf_med=\/upload_files\/pdf\/12751.pdf&manuscript_id=12751","dc:date":"2009","dc:identifier":"http:\/\/journals.tums.ac.ir\/PdfMed.aspx?pdf_med=\/upload_files\/pdf\/12751.pdf&manuscript_id=12751","dc:description":"To determine the rate of different types of arthritis in children. We prepared a retrospective descriptive study and included the whole 100 cases of arthritis referred to 17-Shahrivar Hospital, Rasht, Guilan during a 3 years period. Using their medical files, data including age, sex, season of admission, history of trauma, signs and symptoms, lab findings and duration of hospitalization were collected. SPSS 13.0 (statistical software) applied for statistical analysis. The most common age of involvement ranged 6-9 years. Septic arthritis, brucellosis, and rheumatoid fever were the most frequent causes of arthritis in our study. Fever and restricted range of motion had the highest rate among different signs and symptoms. Lab data demonstrated leukocytosis, positive CRP, and increased ESR among 74, 79.5, and 73 percent of our patients, respectively. According to the high prevalence of septic arthritis and the arthritis due to brucellosis and rheumatoid fever, it seems that mentioned diseases are still major problems in the issue of hygiene management.","dc:title":"Childhood Arthritis: Rate of Different Types"}}}}]},
55 | });
56 |
57 | oabSuccess.discoverCORELinks(this.metadata);
58 |
59 | setTimeout(function() {
60 | var link = $("a", $fixture);
61 | equal(link.length, 3, "Three links added");
62 |
63 | link = $("a:contains('Jaccoud\u2019s Arthritis')", $fixture);
64 | equal(link.length, 1, "Link with 'Jaccoud\u2019s Arthritis' added");
65 | equal(link.attr('href'), "http:\/\/www.jkscience.org\/archive\/111\/18-RL-JACORD%20ARTHRITIS.pdf",
66 | "Link points to correct PDF");
67 |
68 | start();
69 | }, 500);
70 | });
71 |
--------------------------------------------------------------------------------
/oabutton/settings.py:
--------------------------------------------------------------------------------
1 | # Django settings for oabutton project.
2 |
3 | import sys
4 | from os.path import dirname, abspath, join
5 | from mongoengine import connect
6 |
7 | ROOT_PATH = dirname(dirname(abspath(__file__)))
8 | STATIC_PUBLIC = join(ROOT_PATH, 'oabutton/static/public')
9 |
10 | # Start override vars #
11 | DEBUG = False #(sys.argv[1] == 'runserver')
12 | TEMPLATE_DEBUG = DEBUG
13 | HOSTNAME='http://localhost:8000'
14 | # ENd override vars #
15 |
16 | try:
17 | from settings_local import * # NOQA
18 | except:
19 | print "Can't load settings_local - CORE won't work"
20 |
21 |
22 | ADMINS = (
23 | ('Victor Ng', 'victor@crankycoder.com'),
24 | )
25 |
26 | MANAGERS = ADMINS
27 |
28 | DATABASES = {'default': {
29 | 'ENGINE': 'django.db.backends.sqlite3',
30 | 'NAME': 'oabutton.sqlite3', # Path to database file.
31 | 'USER': '', # Not used with sqlite3.
32 | 'PASSWORD': '', # Not used with sqlite3.
33 | # Set to empty string for localhost. Not used with sqlite3.
34 | 'HOST': '',
35 | # Set to empty string for default. Not used with sqlite3.
36 | 'PORT': '',
37 | }}
38 |
39 | # Hosts/domain names that are valid for this site; required if DEBUG is False
40 | # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
41 | ALLOWED_HOSTS = ['*']
42 |
43 | # Local time zone for this installation. Choices can be found here:
44 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
45 | # although not all choices may be available on all operating systems.
46 | # In a Windows environment this must be set to your system time zone.
47 | TIME_ZONE = 'America/Toronto'
48 |
49 | # Language code for this installation. All choices can be found here:
50 | # http://www.i18nguy.com/unicode/language-identifiers.html
51 | LANGUAGE_CODE = 'en-us'
52 |
53 | SITE_ID = 1
54 |
55 | # If you set this to False, Django will make some optimizations so as not
56 | # to load the internationalization machinery.
57 | USE_I18N = True
58 |
59 | # If you set this to False, Django will not format dates, numbers and
60 | # calendars according to the current locale.
61 | USE_L10N = True
62 |
63 | # If you set this to False, Django will not use timezone-aware datetimes.
64 | USE_TZ = True
65 |
66 | # Absolute filesystem path to the directory that will hold user-uploaded files.
67 | # Example: "/home/media/media.lawrence.com/media/"
68 | MEDIA_ROOT = ''
69 |
70 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a
71 | # trailing slash.
72 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
73 | MEDIA_URL = ''
74 |
75 | # Absolute path to the directory static files should be collected to.
76 | # Don't put anything in this directory yourself; store your static files
77 | # in apps' "static/" subdirectories and in STATICFILES_DIRS.
78 | # Example: "/home/media/media.lawrence.com/static/"
79 | STATIC_ROOT = STATIC_PUBLIC
80 |
81 | # URL prefix for static files.
82 | # Example: "http://media.lawrence.com/static/"
83 | STATIC_URL = '/static/'
84 |
85 | # Additional locations of static files
86 | STATICFILES_DIRS = ()
87 |
88 | # List of finder classes that know how to find static files in
89 | # various locations.
90 | STATICFILES_FINDERS = (
91 | 'django.contrib.staticfiles.finders.FileSystemFinder',
92 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
93 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
94 | 'compressor.finders.CompressorFinder',
95 | )
96 |
97 | # Make this unique, and don't share it with anybody.
98 | SECRET_KEY = 'vds2d@yy^4hi_et38)31kkq(pp@06275u&q1tnoz16wo&=127z'
99 |
100 | # List of callables that know how to import templates from various sources.
101 | TEMPLATE_LOADERS = (
102 | ('pyjade.ext.django.Loader', (
103 | 'django.template.loaders.filesystem.Loader',
104 | 'django.template.loaders.app_directories.Loader',
105 | )),
106 | )
107 |
108 | # Production LESS compression via django-compressor
109 | COMPRESS_PRECOMPILERS = (
110 | ('text/less', 'lessc {infile} {outfile}'),
111 | )
112 |
113 | MIDDLEWARE_CLASSES = (
114 | 'django.middleware.common.CommonMiddleware',
115 | 'django.contrib.sessions.middleware.SessionMiddleware',
116 | 'django.middleware.csrf.CsrfViewMiddleware',
117 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
118 | 'django.contrib.messages.middleware.MessageMiddleware',
119 | # Uncomment the next line for simple clickjacking protection:
120 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
121 | )
122 |
123 | ROOT_URLCONF = 'oabutton.urls'
124 |
125 | # Python dotted path to the WSGI application used by Django's runserver.
126 | WSGI_APPLICATION = 'oabutton.wsgi.application'
127 |
128 | TEMPLATE_CONTEXT_PROCESSORS = (
129 | "django.contrib.auth.context_processors.auth",
130 | "django.core.context_processors.debug",
131 | "django.core.context_processors.i18n",
132 | "django.core.context_processors.media",
133 | "django.core.context_processors.request",
134 | "django.core.context_processors.static",
135 | "django.core.context_processors.tz",
136 | "django.contrib.messages.context_processors.messages"
137 | )
138 |
139 | TEMPLATE_DIRS = (
140 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
141 | # Always use forward slashes, even on Windows.
142 | # Don't forget to use absolute paths, not relative paths.
143 | )
144 |
145 | INSTALLED_APPS = (
146 | 'django.contrib.auth',
147 | 'mongoengine.django.mongo_auth',
148 |
149 | 'django.contrib.contenttypes',
150 | 'django.contrib.sessions',
151 |
152 | 'django.contrib.messages',
153 | 'django.contrib.staticfiles',
154 |
155 | 'compressor',
156 |
157 | # The Django admin assumes you're running on a RDBMS and isn't
158 | # suitable for a pure MongoDB
159 | # Do *not* enable it.
160 | 'django.contrib.admin',
161 |
162 | # The bookmarklet app is really just the REST API
163 | 'oabutton.apps.bookmarklet',
164 |
165 | # The web app is the main website
166 | 'oabutton.apps.web',
167 |
168 | 'oabutton.apps.metadata',
169 | )
170 |
171 | # A sample logging configuration. The only tangible logging
172 | # performed by this configuration is to send an email to
173 | # the site admins on every HTTP 500 error when DEBUG=False.
174 | # See http://docs.djangoproject.com/en/dev/topics/logging for
175 | # more details on how to customize your logging configuration.
176 | LOGGING = {
177 | 'version': 1,
178 | 'disable_existing_loggers': False,
179 | 'formatters': {
180 | 'verbose': {
181 | 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
182 | },
183 | 'simple': {
184 | 'format': '%(levelname)s %(message)s'
185 | },
186 | },
187 | 'filters': {
188 | 'require_debug_false': {
189 | '()': 'django.utils.log.RequireDebugFalse'
190 | }
191 | },
192 | 'handlers': {
193 | 'console': {
194 | 'level': 'WARN',
195 | 'class': 'logging.StreamHandler',
196 | 'formatter': 'verbose'
197 | },
198 | 'mail_admins': {
199 | 'level': 'ERROR',
200 | 'filters': ['require_debug_false'],
201 | 'class': 'django.utils.log.AdminEmailHandler'
202 | }
203 | },
204 | 'loggers': {
205 | 'django.request': {
206 | 'handlers': ['mail_admins'],
207 | 'level': 'ERROR',
208 | 'propagate': True,
209 | },
210 | 'oabutton.apps.metadata.views': {
211 | 'handlers': ['console'],
212 | 'level': 'WARN',
213 | },
214 | }
215 | }
216 |
217 | # Honor the 'X-Forwarded-Proto' header for request.is_secure()
218 | SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
219 |
220 | # Bind MongoEngine
221 | connect('oabutton-server-dev', port=27017)
222 |
223 |
224 | # MongoEngine support requires overloading the session storage and the
225 | # authentication backends
226 | SESSION_ENGINE = 'mongoengine.django.sessions'
227 | AUTHENTICATION_BACKENDS = ('mongoengine.django.auth.MongoEngineBackend',)
228 | AUTH_USER_MODEL = 'mongo_auth.MongoUser'
229 | MONGOENGINE_USER_DOCUMENT = 'oabutton.apps.bookmarklet.models.User'
230 |
231 |
--------------------------------------------------------------------------------
/oabutton/static/public/less/app.less:
--------------------------------------------------------------------------------
1 | /* Swatches */
2 |
3 | @oayellow: #ffc425;
4 | @oaorange: #ef5b23;
5 | @oapurple: #7d355a;
6 | @oagreen1: #014d42;
7 | @oagreen2: #008471;
8 | @oagreen3: #37bba4;
9 | @oagreen4: #70c8bc;
10 | @oagreys1: #d6d3e2;
11 | @oagreys2: #a5bfba;
12 |
13 | /* Global styles */
14 |
15 | body, h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
16 | font-family: "Raleway", "Helvetica Neue", Helvetica,Arial,sans-serif;
17 | }
18 |
19 | /* Navigation and header area */
20 |
21 | body { padding-top: 25px; }
22 |
23 | .anchor { padding-top: 50px; margin-top: -50px; }
24 |
25 | a[name] {
26 | padding-top: 75px;
27 | margin-top: -75px;
28 | display: inline-block;
29 | }
30 |
31 | .navbar-header .navbar-brand {
32 | font-size:0px; text-indent:-9999px;
33 | width:16px; height:25px;
34 | margin-top:12px; margin-left:12px;
35 | background:url(../img/oalogo_x_white.png) no-repeat top left;
36 | }
37 |
38 | header {
39 | background:url(../img/bg.jpg) no-repeat;
40 | background-position: 0px 50%;
41 | background-size:100% auto;
42 | text-align: center;
43 |
44 | .container { display:none; }
45 |
46 | a {
47 | display: block;
48 | width:100%; height:225px; max-width: 960px;
49 | font-size: 0px; text-indent: -9999px;
50 | background:url(../img/header_wide.png) no-repeat bottom center;
51 | background-size:80%;
52 | }
53 |
54 | .lead {
55 | position: absolute;
56 | text-align: center;
57 | font-size: 20px;
58 | font-weight: 600;
59 | width: 100%;
60 | left: 0px;
61 | margin-top: 15px;
62 | span {
63 | background-color: @oaorange;
64 | color: white;
65 | padding: 0.4em;
66 | opacity: 0.9;
67 | }
68 | }
69 | }
70 |
71 | #github_ribbon {
72 | position: absolute;
73 | top: 3em;
74 | right: 0;
75 | border: 0;
76 | z-index: 1;
77 | }
78 |
79 | #video-header {
80 | background: url(../img/iconmonstr-video-5.png) no-repeat left center;
81 | background-size: 1em;
82 | padding-left: 1.5em;
83 | }
84 |
85 | .jumbotron { margin-bottom: 0; }
86 |
87 | #start form { border: none; }
88 |
89 | /* Bookmarklet popup */
90 |
91 | #bookmarklet {
92 | display: none;
93 | position: fixed;
94 | top: 15px;
95 | right: 100px;
96 | z-index: 9999;
97 | padding: 10px;
98 | margin: 0;
99 | background: white;
100 | border: 1px solid #ddd;
101 | border-radius: 10px;
102 | }
103 |
104 | #form-bookmarklet {
105 | .checkbox label { font-weight: 700; }
106 | }
107 |
108 | #help-bookmarklet {
109 | display: none;
110 | margin-top: 10px;
111 | margin-bottom: 30px;
112 | background: #eef;
113 | padding: 1em 1em 0.5em 1em;
114 | }
115 |
116 | .wedge-up {
117 | display: block;
118 | width: 15px;
119 | height: 15px;
120 | border-top: 15px solid transparent;
121 | border-left: 15px solid white;
122 | position: absolute;
123 | margin-top: -25px;
124 | }
125 |
126 | .modal-backdrop.in {
127 | opacity: .8;
128 | filter: alpha(opacity=80);
129 | }
130 |
131 | /* Activity map */
132 |
133 | #world, #map {
134 | height: 500px;
135 | width: 100%;
136 | margin-top: -20px;
137 | }
138 | #world {
139 | .underlay {
140 | display: none;
141 | position: absolute;
142 | left: 0px;
143 | bottom: 0px;
144 | width: 84%;
145 | margin: 0 8%;
146 | padding: 1em 0;
147 | z-index: 99;
148 | background: @oayellow;
149 |
150 | .lead {
151 | background: #fff;
152 | text-align: center;
153 | margin-bottom: 10px;
154 | }
155 |
156 | p { padding: 0 1em; font-size: 110%; }
157 | }
158 | }
159 |
160 | #counter {
161 | font-weight: bold;
162 | font-size: 120%;
163 | }
164 |
165 | .thumbnail .caption {
166 | padding: 0px;
167 |
168 | p { font-size: 95%; }
169 | }
170 |
171 | /* Content areas */
172 |
173 | h2 {
174 | color: #494949;
175 | font-size: 40px;
176 | text-align: center;
177 | padding-top: 0;
178 | margin-top: 0;
179 | margin-bottom: 15px;
180 | }
181 |
182 | h3 {
183 | color: #555;
184 | font-size: 19px;
185 | text-align: center;
186 | padding-top: 15px;
187 | margin-top: 0;
188 | margin-bottom: 1em;
189 | }
190 |
191 | h3.overline {
192 | border-top: 1px solid #aaa;
193 | }
194 |
195 | a[data-toggle] {
196 | cursor: pointer;
197 | }
198 |
199 | #intro, #contribute, #thanks {
200 |
201 | padding: 2em 3em;
202 |
203 | p { line-height: 1.7; }
204 |
205 | .row {
206 | border-left: 7px solid transparent;
207 | border-right: 7px solid transparent;
208 | padding: 0 1.5em;
209 | }
210 | .row.hilite-left {
211 | border-left: 7px solid @oaorange;
212 | }
213 | .row.hilite-right {
214 | border-right: 7px solid @oaorange;
215 | }
216 | }
217 |
218 | /* Container colors */
219 | #thanks { background: #ffd; }
220 | #intro, #footer { background: #eee; }
221 |
222 | .buttons {
223 | margin-top: 2em;
224 | text-align: center;
225 |
226 | a { text-decoration: none !important; }
227 |
228 | button {
229 | font-size: 20px;
230 | padding: 4px 10px;
231 | border-color: #444;
232 | color: #000;
233 | margin: 0 20px;
234 | }
235 | }
236 |
237 | #contribute {
238 | background: #fff;
239 | }
240 |
241 | @thumbsize: 48;
242 | @captwidth: 400;
243 | @captheight: 156;
244 | @captmargin: @captwidth - @thumbsize;
245 | @thumbmargin: @captmargin + @thumbsize/2.4;
246 | #thanks .team {
247 | ul { text-align: left; list-style: none; }
248 | .thumbnails {
249 |
250 | li { display: inline-block; margin: 0 2px; }
251 |
252 | .wedge-up { border-left-color: @oaorange; margin-top:-19px; }
253 |
254 | .thumb {
255 | width: unit(@thumbsize, px);
256 | height: unit(@thumbsize, px);
257 | overflow: hidden;
258 | display: inline-block;
259 | img { width: 100%; }
260 | }
261 |
262 | li:hover, li.hover { .thumb { opacity: 0.1; } }
263 |
264 | li.right {
265 | .caption { margin-left:unit(-@captmargin, px); }
266 | .wedge-up {
267 | margin-left:unit(@thumbmargin, px);
268 | border-left: none;
269 | border-right: 15px solid @oaorange;
270 | }
271 | }
272 |
273 | .caption {
274 | position: absolute; z-index: 99;
275 | margin: 0;
276 | width: unit(@captwidth, px);
277 | height: unit(@captheight, px);
278 | max-width: 90%;
279 | padding: 4px;
280 | border: 2px solid @oaorange;
281 | background: white;
282 | font-size: 20px;
283 |
284 | .name {
285 | font-size: 23px;
286 | font-weight: bold;
287 | }
288 |
289 | p {
290 | margin-top: 4px;
291 | font-size: 15px;
292 | line-height: 1.2;
293 | }
294 |
295 | .large {
296 | height: unit(@thumbsize*3, px);
297 | max-width: unit(@thumbsize*3, px);
298 | float: left; margin-right: 5px;
299 |
300 | overflow: hidden;
301 | img { height: 144px; }
302 | }
303 |
304 | .links {
305 | position: absolute;
306 | left: unit(@thumbsize*3, px);
307 | bottom: 5px;
308 | }
309 |
310 | .web, .twitter {
311 | display: inline-block;
312 | width: auto; height: 24px;
313 | font-size: 18px;
314 | margin-left: 10px;
315 | padding-left: 27px;
316 | background-size: 24px 24px;
317 | background-repeat: no-repeat;
318 | background-position: left;
319 | }
320 |
321 | .web { background-image: url(../img/iconmonstr-globe-3.png); }
322 | .twitter { background-image: url(../img/iconmonstr-twitter-4.png); }
323 | }
324 |
325 | li .caption { display:none; }
326 | li:hover, li.hover { .caption { display: block; } }
327 | }
328 | }
329 |
330 | #thanks .orgs {
331 | li { width: 25%; float: left; }
332 | p {
333 | display: block; clear: both;
334 | font-size: 15px;
335 | padding-top:1em; text-align: center;
336 | }
337 | }
338 |
339 | #footer {
340 | padding-top: 2em;
341 |
342 | .icon {
343 | height: 32px;
344 | width: 32px;
345 | display: inline-block;
346 | background-repeat: no-repeat;
347 | background-position: 50% 50%;
348 | background-size: 100%;
349 | position: relative;
350 | font-size: 0px;
351 | text-indent: -9999px;
352 | margin: 0 25px 0 0;
353 | }
354 | .icon:hover { opacity: 0.5; }
355 | .twitter { background-image: url(../img/webicon-twitter.png); }
356 | .facebook { background-image: url(../img/webicon-facebook.png); }
357 | .wordpress { background-image: url(../img/webicon-wordpress.png); }
358 | }
359 |
360 | .license {
361 | font-size:90%;
362 | img {
363 | float: left;
364 | padding-top: 1.5em;
365 | padding-right: 1em;
366 | }
367 | }
368 |
369 | /* Responsive styles */
370 | @media screen and (max-width: 768px) {
371 | body { padding-top: 0px; }
372 | header a { background-size:100%; }
373 | header .lead { font-size:15px; position:relative; }
374 | }
375 | @media screen and (max-width: 520px) {
376 | header a {
377 | height: 110px; position: absolute;
378 | background-image: url(../img/header_needaccess.png);
379 | }
380 | header .lead { visibility: hidden; }
381 | #github_ribbon { display: none; }
382 | }
--------------------------------------------------------------------------------
/oabutton/apps/web/templates/web/index.jade:
--------------------------------------------------------------------------------
1 | extends web/layout
2 | block body
3 | #top
4 | a(name='top')
5 |
6 | // Github ribbon
7 | a(href='https://github.com/OAButton/OAButton')
8 | img#github_ribbon(
9 | src='https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png',
10 | alt='Fork me on GitHub')
11 |
12 | .navbar.navbar-inverse.navbar-fixed-top(role='navigation')
13 | .container
14 | .navbar-header
15 | button.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse')
16 | span.icon-bar
17 | span.icon-bar
18 | span.icon-bar
19 | a.navbar-brand(href='#') Open Access Button
20 | .navbar-collapse.collapse
21 | ul.nav.navbar-nav
22 | li
23 | a(href='#top') Get the button
24 | li
25 | a(href='#world') See the map
26 | li
27 | a(href='#contribute') Contribute
28 | li
29 | a(href='#thanks') Meet the team
30 | li
31 | a(href='#contact') Contact and follow
32 |
33 | header.jumbotron.subhead
34 | .container
35 | h1 Need Access to Research?
36 | h2 Sign up below to get your Open Access Button
37 | a(href="#start", data-toggle="modal", data-target="#video-modal", alt="Need access to research?", title="Learn more about the project in this video")
38 | | Learn more about the project in this video
39 | .lead
40 | span
41 | | Tearing down barriers to accessing research, one click at a time
42 |
43 | .modal.fade(id="video-modal", tabindex="-1", role="dialog", aria-labelledby="video-header", aria-hidden="true")
44 | .modal-dialog
45 | .modal-content
46 | .modal-header
47 | button.close(type="button", data-dismiss="modal", aria-hidden="true") ×
48 | h4.modal-title(id="video-header")
49 | | Introduction video
50 | .modal-body
51 | iframe(width="538", height="303", src="//www.youtube-nocookie.com/embed/3X_59G06RZM?rel=0", frameborder="0", allowfullscreen)
52 | .modal-footer
53 | button.btn.btn-default(type="button", data-dismiss="modal") Close
54 |
55 | #start
56 | .container.center
57 | block start
58 |
59 | #world
60 | a(name='world')
61 | .container
62 | #map
63 | .underlay
64 | .lead
65 | span(id='counter')
66 | {{count|force_escape}}
67 | span
68 | | Paywalls Hit
69 | p
70 | | This map displays people being denied access to the research they both need and paid for. Put yourself on the map using the Open Access Button to tell the world you are being denied access to knowledge. Using the Open Access Button will make the individual moments of injustice and frustration visible to the world.
71 |
72 | #intro
73 | a(name='intro')
74 | .container
75 | h2 What is this about?
76 | .row.hilite-left
77 | .col-md-12
78 | p
79 | | People are denied access to research hidden behind paywalls every day. This problem is invisible, but it slows innovation, kills curiosity and harms patients. This is an indictment of the current system.
80 | a(href="http://www.youtube.com/watch?v=L5rVH1KGBCY") Open Access
81 | | has given us the solution to this problem by allowing everyone to read and re-use research.
82 | | We created the
83 | i Open Access Button
84 | | to track the impact of paywalls and help you get access to the research you need. By using the button you’ll help show the impact of this problem, drive awareness of the issue, and help change the system. Furthermore, the
85 | i Open Access Button
86 | | has several ways of helping you get access to the research you need right now.
87 |
88 | #contribute
89 | a(name='contribute')
90 | .container
91 | h2 Get involved.
92 | .row.hilite-right
93 | .col-md-12
94 | p
95 | | The first step is using the Open Access Button (and you are using it, daily, on every paywall, right?). But don’t think that’s all there is to do! This project was made possible by developers, advocates, students and general clever folk from Open community and we need continued support to take this to the next level. Of course, the code, text, and data we’ve pulled together are openly available, so you can innovate and advocate with it. If you can, donate to the project to help us support and maintain service as well as helping us with our future development plans. Bottom line, we’d love to hear from you, so whether it’s a suggestion, virtual pat on the back, or, dare I say a bug you’ve noticed, get in touch.
96 |
97 | .row.buttons
98 | .col-md-12
99 | a(href="mailto:oabutton+bug@gmail.com")
100 | button.btn.btn-default.bug(type="button")
101 | | Report a bug
102 | a(href="https://www.charitycheckout.co.uk/1111824/OpenAccessButton")
103 | button.btn.btn-warning.donate(type="button")
104 | | Donate!
105 | a(href="mailto:oabutton+suggestion@gmail.com")
106 | button.btn.btn-success.suggest(type="button")
107 | | Suggestions
108 |
109 | #thanks
110 | a(name='thanks')
111 | .container
112 | .row.team
113 | .col-md-12
114 | h3.overline Meet the team of people and organisations who made this a reality
115 | ul.thumbnails
116 | each person in team_data
117 | li
118 | a.thumb(href="#{person['link']}", style="visibility:hidden")
119 | img(src="#{person['thumb']}")
120 | .caption
121 | i.wedge-up
122 | .large
123 | img(src="#{person['thumb']}")
124 | a.name(href="#{person['link']}") {{ person.name }}
125 | p {{ person.blurb }}
126 | .links
127 | if person.twitter
128 | a.twitter(href="http://twitter.com/#{person['twitter']}") Twitter
129 | .row.orgs
130 | .col-md-12
131 | h3 Many thanks to all of you who helped along the way
132 | ul
133 | each org in thanks_data
134 | li
135 | a(href="#{org['link']}")
136 | | {{ org.name }}
137 | p
138 | b +
139 | | Everyone who joined the
140 | a(href="https://www.thunderclap.it/en/projects/5675-open-access-button-launch") Thunderclap
141 | |, sent messages of support and suggestions!
142 |
143 |
144 | #footer
145 | a(name='contact')
146 | .container
147 | .row
148 | .col-md-3.col-sm-3
149 | p
150 | b INFO
151 | p
152 | a(href="http://blog.openaccessbutton.org")
153 | | Project blog
154 | p
155 | a(href="https://groups.google.com/d/forum/open-access-button-general")
156 | | Join the community
157 | p
158 | a(href="http://oabutton.wordpress.com/2013/11/17/disclaimer/")
159 | | Terms of use
160 | .col-md-3.col-sm-3
161 | p
162 | b ABOUT
163 | p
164 | a(href="mailto:oabutton+press@gmail.com")
165 | | Media inquiries
166 | p
167 | a(href="https://github.com/oabutton")
168 | | Get the code
169 | p
170 | a(href="mailto:oabutton+data@gmail.com")
171 | | Get the data
172 | .col-md-6.col-sm-6
173 | p
174 | a.icon.twitter(href="https://twitter.com/oa_button") Twitter
175 | a.icon.facebook(href="https://www.facebook.com/openaccessbutton") Facebook
176 | a.icon.wordpress(href="http://oabutton.wordpress.com/") Wordpress
177 |
178 | p.license
179 | a(rel="license", href="http://creativecommons.org/licenses/by/3.0/")
180 | img(alt="Creative Commons License", style="border-width:0", src="http://i.creativecommons.org/l/by/3.0/88x31.png")
181 | br
182 | | The
183 | span(xmlns:dct="http://purl.org/dc/terms/", property="dct:title") Open Access Button
184 | | is licensed under a
185 | a(rel="license", href="http://creativecommons.org/licenses/by/3.0/") Creative Commons Attribution 3.0 Unported License
186 | |.
187 |
--------------------------------------------------------------------------------
/oabutton/static/public/css/styles.css:
--------------------------------------------------------------------------------
1 | @import "../css/MarkerCluster.css";
2 |
3 | @import "../css/MarkerCluster.Default.css";
4 | /* Don't edit this CSS file. It's generated using lessc */
5 | /* Swatches */
6 | /* Global styles */
7 | body,
8 | h1,
9 | h2,
10 | h3,
11 | h4,
12 | h5,
13 | h6,
14 | .h1,
15 | .h2,
16 | .h3,
17 | .h4,
18 | .h5,
19 | .h6 {
20 | font-family: "Raleway", "Helvetica Neue", Helvetica, Arial, sans-serif;
21 | }
22 | /* Navigation and header area */
23 | body {
24 | padding-top: 25px;
25 | }
26 | .anchor {
27 | padding-top: 50px;
28 | margin-top: -50px;
29 | }
30 | a[name] {
31 | padding-top: 75px;
32 | margin-top: -75px;
33 | display: inline-block;
34 | }
35 | .navbar-header .navbar-brand {
36 | font-size: 0px;
37 | text-indent: -9999px;
38 | width: 16px;
39 | height: 25px;
40 | margin-top: 12px;
41 | margin-left: 12px;
42 | background: url(../img/oalogo_x_white.png) no-repeat top left;
43 | }
44 | header {
45 | background: url(../img/bg.jpg) no-repeat;
46 | background-position: 0px 50%;
47 | background-size: 100% auto;
48 | text-align: center;
49 | }
50 | header .container {
51 | display: none;
52 | }
53 | header a {
54 | display: block;
55 | width: 100%;
56 | height: 225px;
57 | max-width: 960px;
58 | font-size: 0px;
59 | text-indent: -9999px;
60 | background: url(../img/header_wide.png) no-repeat bottom center;
61 | background-size: 80%;
62 | }
63 | header .lead {
64 | position: absolute;
65 | text-align: center;
66 | font-size: 20px;
67 | font-weight: 600;
68 | width: 100%;
69 | left: 0px;
70 | margin-top: 15px;
71 | }
72 | header .lead span {
73 | background-color: #ef5b23;
74 | color: white;
75 | padding: 0.4em;
76 | opacity: 0.9;
77 | }
78 | #github_ribbon {
79 | position: absolute;
80 | top: 3em;
81 | right: 0;
82 | border: 0;
83 | z-index: 1;
84 | }
85 | #video-header {
86 | background: url(../img/iconmonstr-video-5.png) no-repeat left center;
87 | background-size: 1em;
88 | padding-left: 1.5em;
89 | }
90 | .jumbotron {
91 | margin-bottom: 0;
92 | }
93 | #start form {
94 | border: none;
95 | }
96 | /* Bookmarklet popup */
97 | #bookmarklet {
98 | display: none;
99 | position: fixed;
100 | top: 15px;
101 | right: 100px;
102 | z-index: 9999;
103 | padding: 10px;
104 | margin: 0;
105 | background: white;
106 | border: 1px solid #ddd;
107 | border-radius: 10px;
108 | }
109 | #form-bookmarklet .checkbox label {
110 | font-weight: 700;
111 | }
112 | #help-bookmarklet {
113 | display: none;
114 | margin-top: 10px;
115 | margin-bottom: 30px;
116 | background: #eef;
117 | padding: 1em 1em 0.5em 1em;
118 | }
119 | .wedge-up {
120 | display: block;
121 | width: 15px;
122 | height: 15px;
123 | border-top: 15px solid transparent;
124 | border-left: 15px solid white;
125 | position: absolute;
126 | margin-top: -25px;
127 | }
128 | .modal-backdrop.in {
129 | opacity: .8;
130 | filter: alpha(opacity=80);
131 | }
132 | /* Activity map */
133 | #world,
134 | #map {
135 | height: 500px;
136 | width: 100%;
137 | margin-top: -20px;
138 | }
139 | #world .underlay {
140 | display: none;
141 | position: absolute;
142 | left: 0px;
143 | bottom: 0px;
144 | width: 84%;
145 | margin: 0 8%;
146 | padding: 1em 0;
147 | z-index: 99;
148 | background: #ffc425;
149 | }
150 | #world .underlay .lead {
151 | background: #fff;
152 | text-align: center;
153 | margin-bottom: 10px;
154 | }
155 | #world .underlay p {
156 | padding: 0 1em;
157 | font-size: 110%;
158 | }
159 | #counter {
160 | font-weight: bold;
161 | font-size: 120%;
162 | }
163 | .thumbnail .caption {
164 | padding: 0px;
165 | }
166 | .thumbnail .caption p {
167 | font-size: 95%;
168 | }
169 | /* Content areas */
170 | h2 {
171 | color: #494949;
172 | font-size: 40px;
173 | text-align: center;
174 | padding-top: 0;
175 | margin-top: 0;
176 | margin-bottom: 15px;
177 | }
178 | h3 {
179 | color: #555;
180 | font-size: 19px;
181 | text-align: center;
182 | padding-top: 15px;
183 | margin-top: 0;
184 | margin-bottom: 1em;
185 | }
186 | h3.overline {
187 | border-top: 1px solid #aaa;
188 | }
189 | a[data-toggle] {
190 | cursor: pointer;
191 | }
192 | #intro,
193 | #contribute,
194 | #thanks {
195 | padding: 2em 3em;
196 | }
197 | #intro p,
198 | #contribute p,
199 | #thanks p {
200 | line-height: 1.7;
201 | }
202 | #intro .row,
203 | #contribute .row,
204 | #thanks .row {
205 | border-left: 7px solid transparent;
206 | border-right: 7px solid transparent;
207 | padding: 0 1.5em;
208 | }
209 | #intro .row.hilite-left,
210 | #contribute .row.hilite-left,
211 | #thanks .row.hilite-left {
212 | border-left: 7px solid #ef5b23;
213 | }
214 | #intro .row.hilite-right,
215 | #contribute .row.hilite-right,
216 | #thanks .row.hilite-right {
217 | border-right: 7px solid #ef5b23;
218 | }
219 | /* Container colors */
220 | #thanks {
221 | background: #ffd;
222 | }
223 | #intro,
224 | #footer {
225 | background: #eee;
226 | }
227 | .buttons {
228 | margin-top: 2em;
229 | text-align: center;
230 | }
231 | .buttons a {
232 | text-decoration: none !important;
233 | }
234 | .buttons button {
235 | font-size: 20px;
236 | padding: 4px 10px;
237 | border-color: #444;
238 | color: #000;
239 | margin: 0 20px;
240 | }
241 | #contribute {
242 | background: #fff;
243 | }
244 | #thanks .team ul {
245 | text-align: left;
246 | list-style: none;
247 | }
248 | #thanks .team .thumbnails li {
249 | display: inline-block;
250 | margin: 0 2px;
251 | }
252 | #thanks .team .thumbnails .wedge-up {
253 | border-left-color: #ef5b23;
254 | margin-top: -19px;
255 | }
256 | #thanks .team .thumbnails .thumb {
257 | width: 48px;
258 | height: 48px;
259 | overflow: hidden;
260 | display: inline-block;
261 | }
262 | #thanks .team .thumbnails .thumb img {
263 | width: 100%;
264 | }
265 | #thanks .team .thumbnails li:hover .thumb,
266 | #thanks .team .thumbnails li.hover .thumb {
267 | opacity: 0.1;
268 | }
269 | #thanks .team .thumbnails li.right .caption {
270 | margin-left: -352px;
271 | }
272 | #thanks .team .thumbnails li.right .wedge-up {
273 | margin-left: 372px;
274 | border-left: none;
275 | border-right: 15px solid #ef5b23;
276 | }
277 | #thanks .team .thumbnails .caption {
278 | position: absolute;
279 | z-index: 99;
280 | margin: 0;
281 | width: 400px;
282 | height: 156px;
283 | max-width: 90%;
284 | padding: 4px;
285 | border: 2px solid #ef5b23;
286 | background: white;
287 | font-size: 20px;
288 | }
289 | #thanks .team .thumbnails .caption .name {
290 | font-size: 23px;
291 | font-weight: bold;
292 | }
293 | #thanks .team .thumbnails .caption p {
294 | margin-top: 4px;
295 | font-size: 15px;
296 | line-height: 1.2;
297 | }
298 | #thanks .team .thumbnails .caption .large {
299 | height: 144px;
300 | max-width: 144px;
301 | float: left;
302 | margin-right: 5px;
303 | overflow: hidden;
304 | }
305 | #thanks .team .thumbnails .caption .large img {
306 | height: 144px;
307 | }
308 | #thanks .team .thumbnails .caption .links {
309 | position: absolute;
310 | left: 144px;
311 | bottom: 5px;
312 | }
313 | #thanks .team .thumbnails .caption .web,
314 | #thanks .team .thumbnails .caption .twitter {
315 | display: inline-block;
316 | width: auto;
317 | height: 24px;
318 | font-size: 18px;
319 | margin-left: 10px;
320 | padding-left: 27px;
321 | background-size: 24px 24px;
322 | background-repeat: no-repeat;
323 | background-position: left;
324 | }
325 | #thanks .team .thumbnails .caption .web {
326 | background-image: url(../img/iconmonstr-globe-3.png);
327 | }
328 | #thanks .team .thumbnails .caption .twitter {
329 | background-image: url(../img/iconmonstr-twitter-4.png);
330 | }
331 | #thanks .team .thumbnails li .caption {
332 | display: none;
333 | }
334 | #thanks .team .thumbnails li:hover .caption,
335 | #thanks .team .thumbnails li.hover .caption {
336 | display: block;
337 | }
338 | #thanks .orgs li {
339 | width: 25%;
340 | float: left;
341 | }
342 | #thanks .orgs p {
343 | display: block;
344 | clear: both;
345 | font-size: 15px;
346 | padding-top: 1em;
347 | text-align: center;
348 | }
349 | #footer {
350 | padding-top: 2em;
351 | }
352 | #footer .icon {
353 | height: 32px;
354 | width: 32px;
355 | display: inline-block;
356 | background-repeat: no-repeat;
357 | background-position: 50% 50%;
358 | background-size: 100%;
359 | position: relative;
360 | font-size: 0px;
361 | text-indent: -9999px;
362 | margin: 0 25px 0 0;
363 | }
364 | #footer .icon:hover {
365 | opacity: 0.5;
366 | }
367 | #footer .twitter {
368 | background-image: url(../img/webicon-twitter.png);
369 | }
370 | #footer .facebook {
371 | background-image: url(../img/webicon-facebook.png);
372 | }
373 | #footer .wordpress {
374 | background-image: url(../img/webicon-wordpress.png);
375 | }
376 | .license {
377 | font-size: 90%;
378 | }
379 | .license img {
380 | float: left;
381 | padding-top: 1.5em;
382 | padding-right: 1em;
383 | }
384 | /* Responsive styles */
385 | @media screen and (max-width: 768px) {
386 | body {
387 | padding-top: 0px;
388 | }
389 | header a {
390 | background-size: 100%;
391 | }
392 | header .lead {
393 | font-size: 15px;
394 | position: relative;
395 | }
396 | }
397 | @media screen and (max-width: 520px) {
398 | header a {
399 | height: 110px;
400 | position: absolute;
401 | background-image: url(../img/header_needaccess.png);
402 | }
403 | header .lead {
404 | visibility: hidden;
405 | }
406 | #github_ribbon {
407 | display: none;
408 | }
409 | }
410 | .form-bookmarklet {
411 | /* max-width: 300px; */
412 |
413 | padding: 19px 29px 29px;
414 | margin: 0 auto 20px;
415 | background-color: #fff;
416 | border: 1px solid #e5e5e5;
417 | -webkit-border-radius: 5px;
418 | -moz-border-radius: 5px;
419 | border-radius: 5px;
420 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
421 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
422 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
423 | }
424 | .form-bookmarklet .form-bookmarklet-heading,
425 | .form-bookmarklet .checkbox {
426 | margin-bottom: 10px;
427 | }
428 | .form-bookmarklet input[type="text"],
429 | .form-bookmarklet input[type="password"],
430 | .form-bookmarklet select {
431 | font-size: 16px;
432 | height: auto;
433 | margin-bottom: 15px;
434 | padding: 7px 9px;
435 | width: 100%;
436 | }
437 | .form-bookmarklet button {
438 | font-size: 16px;
439 | height: auto;
440 | margin-bottom: 15px;
441 | padding: 7px 9px;
442 | clear: both;
443 | width: 100%;
444 | }
445 |
--------------------------------------------------------------------------------
/oabutton/common/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: latin-1
2 | from django import forms
3 |
4 |
5 | class SigninForm(forms.Form):
6 | PROFESSION_CHOICES = (('Student', 'Student'),
7 | ('Doctor', 'Doctor'),
8 | ('Patient', 'Patient'),
9 | ('Advocate', 'Advocate'),
10 | ('Academic', 'Academic'),
11 | ('Researcher', 'Researcher'),
12 | ('Librarian', 'Librarian'),
13 | ('Other', 'Other'),
14 | ('Undisclosed', 'Prefer not to say'))
15 |
16 | email = forms.EmailField(required=True,
17 | label='Email address',
18 | widget=forms.TextInput(attrs={'placeholder': 'Email address (required)'}))
19 |
20 | name = forms.CharField(required=True,
21 | label="Name",
22 | widget=forms.TextInput(attrs={'placeholder': 'Name (required, preferably full name)'}))
23 |
24 | profession = forms.ChoiceField(required=True,
25 | label="Profession",
26 | choices=PROFESSION_CHOICES)
27 |
28 | confirm_public = forms.BooleanField(label="I understand that information obtained by this button will be publicly accessible", required=True)
29 |
30 | mailinglist = forms.BooleanField(label="I would like to be added to the Open Access Button Mailing List", required=False, initial=True)
31 |
32 |
33 | class Bookmarklet(forms.Form):
34 | user_id = forms.CharField(widget=forms.HiddenInput, required=True)
35 | accessed = forms.CharField(widget=forms.HiddenInput, required=False)
36 | coords = forms.CharField(widget=forms.HiddenInput, required=False)
37 |
38 | location = forms.CharField(required=False,
39 | label="Location",
40 | widget=forms.TextInput(attrs={
41 | 'placeholder': "e.g. London, United Kingdom",
42 | 'class': "form-control input-block-level",
43 | 'required': True}))
44 |
45 | doi = forms.CharField(required=False, label="Digital Object Identifier (DOI)",
46 | widget=forms.TextInput(attrs={'class': "form-control input-block-level"},
47 | ))
48 |
49 | url = forms.URLField(required=True, label='Article URL',
50 | widget=forms.TextInput(attrs={'placeholder':
51 | "http://www.publisher.com/journal?id=XXXX", 'class': "form-control input-block-level"}))
52 |
53 | story = forms.CharField(required=False, label="Why do you need access?",
54 | widget=forms.Textarea(attrs={'rows': "4",
55 | 'placeholder': "e.g. I'm trying to save lives, dammit!",
56 | 'class': "form-control input-block-level"}))
57 |
58 | description = forms.CharField(required=False, label="Description",
59 | widget=forms.Textarea(attrs={'placeholder': 'Title, Authors, Journal', 'data-remember': "data-remember",
60 | 'rows': '4', 'class': "form-control input-block-level"}))
61 |
62 | teamdata = [{"name": "Joseph McArthur",
63 | "link": "http://twitter.com/Mcarthur_Joe",
64 | "thumb": "/static/img/photo-joe.jpg",
65 | "twitter": "Mcarthur_Joe",
66 | "blurb": "Founder, project lead and apparently also a pharmacology student"
67 | }, {
68 | "name": "David Carroll",
69 | "link": "http://twitter.com/davidecarroll",
70 | "thumb": "/static/img/photo-david.jpg",
71 | "twitter": "davidecarroll",
72 | "blurb": "Founder, medical student and twitter addict"
73 | }, {
74 | "name": "Nicholas Ng",
75 | "link": "http://twitter.com/nicholascwng",
76 | "thumb": "https://secure.gravatar.com/avatar/9637895e310caf25237e89155157b2a7?s=144",
77 | "twitter": "nicholascwng",
78 | "blurb": "Awesome developer from the BMJ Hackday who was instrumental in getting us 3rd place"
79 | }, {
80 | "name": "Andy Lulham",
81 | "link": "http://twitter.com/andylolz",
82 | "thumb": "https://1.gravatar.com/avatar/bbb9eb1af3b427f8259df33f6e8844aa?s=144",
83 | "twitter": "andylolz",
84 | "blurb": "Lead developer and central to the project from the first second at the BMJ hackday"
85 | }, {
86 | "name": "Florian Rathgeber",
87 | "link": "http://twitter.com/frathgeber",
88 | "thumb": "https://lh5.googleusercontent.com/-TQyLDuEMj1E/Umm1CqZohdI/AAAAAAAAZAA/PdCXgUG5d0Y/s144-no",
89 | "twitter": "frathgeber",
90 | "blurb": "Joined the project at the BMJ hackday and helped throughout providing solutions to our many problems"
91 | }, {
92 | "name": "Jez Cope",
93 | "link": "#",
94 | "thumb": "https://2.gravatar.com/avatar/6c1c67fa04add9cada803f13ae2ff050?s=144",
95 | "blurb": "Lead Developer who designed and implemented a way for us to link papers behind paywalls to available copies"
96 | }, {
97 | "name": "Alf Eaton",
98 | "link": "http://twitter.com/invisiblecomma",
99 | "thumb": "https://lh3.googleusercontent.com/-EHMuXvuZH1k/AAAAAAAAAAI/AAAAAAAAFeE/Z93Ix4IW-BY/s120-c/photo.jpg",
100 | "twitter": "invisiblecomma",
101 | "blurb": "Developer at PeerJ who lended a hand at several points"
102 | }, {
103 | "name": "Ayesha Garrett",
104 | "link": "http://londonlime.net/",
105 | "thumb": "http://behance.vo.llnwd.net/profiles17/614780/851b0bf48a4eb7968873cfa622662c58.jpg",
106 | "twitter": "londonlime",
107 | "blurb": "Helped design much of the imaging around the project"
108 | }, {
109 | "name": "Victor Ng",
110 | "link": "#",
111 | "thumb": "http://www.gravatar.com/avatar/c5ab90719801dfa47055338ba47f5580.png?s=144",
112 | "blurb": "One of our best developers, instrumental in bring it to completion. Elsevier's biggest fan"
113 | }, {
114 | "name": "Oleg Lavrovsky",
115 | "link": "http://utou.ch",
116 | "thumb": "https://pbs.twimg.com/profile_images/378800000404422761/3bde338af1f5fcdbe24dda38ed36b9d1.jpeg",
117 | "twitter": "loleg",
118 | "blurb": "Lead designer and web developer, also creator of an awesome spin off, the Open Data Button"
119 | }, {
120 | "name": "Tom Pollard",
121 | "link": "https://twitter.com/tompollard",
122 | "thumb": "http://www.ucl.ac.uk/mssl/space-medicine/people/TomPollardPhoto",
123 | "twitter": "tompollard",
124 | "blurb": "Developer. PhD student in University College London. Co-founder of Ubiquity Press"
125 | }, {
126 | "name": "Martin Paul Eve",
127 | "link": "#",
128 | "thumb": "https://0.gravatar.com/avatar/3645eb2857da226a58ca23a582a0b859?s=144",
129 | "blurb": "Developer. Lecturer in English Literature. Director of Open Library of Humanities"
130 | }, {
131 | "name": "Emanuil Tolev",
132 | "link": "#",
133 | "thumb": "https://pbs.twimg.com/profile_images/378800000606651539/5651bffd1905807bcdd4b619d0a7e13d.jpeg",
134 | "blurb": "Developer. Computer Science Student. Associate at Cottage Labs"
135 | }, {
136 | "name": "Cameron Stocks",
137 | "link": "http://twitter.com/cam_stocks",
138 | "thumb": "https://pbs.twimg.com/profile_images/3666850209/e8c8b7281daccb2fcccae1f538c6d82a_bigger.jpeg",
139 | "twitter": "cam_stocks",
140 | "blurb": "National Director of Medsin, the UK’s student global health network, and founder"
141 | }, {
142 | "name": "Nicole Allen",
143 | "link": "https://twitter.com/txtbks",
144 | "thumb": "https://pbs.twimg.com/profile_images/3151008497/5c42187852b2ef7e5492a6f6e792a21b.jpeg",
145 | "twitter": "txtbks",
146 | "blurb": "Open Educational Resources Program Director at SPARC who helped with training and project planning"
147 | }, {
148 | "name": "Nicholas Shockey",
149 | "link": "#",
150 | "thumb": "http://conf11.freeculture.org/files/2011/01/Nick-Shockey1.jpg",
151 | "blurb": "Director of the Right to Research Coalition and of Student Advocacy at SPARC, who provided invaluable input at all stages"
152 | }, {
153 | "name": "Medsin",
154 | "link": "http://www.medsin.org/",
155 | "thumb": "/static/img/logo-medsin.jpg",
156 | "twitter": "medsin",
157 | "blurb": "The Open Access Button is a Medsin programme"
158 | }, {
159 | "name": "Right to Research Coalition",
160 | "link": "http://www.righttoresearch.org/",
161 | "thumb": "http://www.righttoresearch.org/bm~pix/r2r-logo.png",
162 | "twitter": "R2RC",
163 | "blurb": "An invaluable source of support, ideas and money"
164 | }
165 | ]
166 |
167 | thanksdata = [{
168 | "link": "http://opensciencefederation.com/",
169 | "name": "Open Science Federation"
170 | },{
171 | "link": "http://originalcontentlondon.com/",
172 | "name": "Original Content London"
173 | },{
174 | "link": "https://twitter.com/McDawg",
175 | "name": "Graham Steel"
176 | },{
177 | "link": "http://okfn.org/",
178 | "name": "Open Knowledge Foundation"
179 | },{
180 | "link": "http://rewiredstate.org/",
181 | "name": "Rewired State"
182 | },{
183 | "link": "http://www.bmj.com/",
184 | "name": "BMJ"
185 | },{
186 | "link": "http://www.plos.org/",
187 | "name": "PLOS"
188 | },{
189 | "link": "https://twitter.com/Protohedgehog",
190 | "name": "Jon Tennant"
191 | },{
192 | "link": "https://twitter.com/petermurrayrust",
193 | "name": "Peter Murray-Rust"
194 | },{
195 | "link": "http://sparc.arl.org/",
196 | "name": "SPARC"
197 | },{
198 | "link": "https://twitter.com/CameronNeylon",
199 | "name": "Cameron Neylon"
200 | },{
201 | "link": "https://twitter.com/evomri",
202 | "name": "Daniel Mietchen"
203 | }]
204 |
--------------------------------------------------------------------------------
/oabutton/static/public/css/leaflet.css:
--------------------------------------------------------------------------------
1 | /* required styles */
2 |
3 | .leaflet-map-pane,
4 | .leaflet-tile,
5 | .leaflet-marker-icon,
6 | .leaflet-marker-shadow,
7 | .leaflet-tile-pane,
8 | .leaflet-tile-container,
9 | .leaflet-overlay-pane,
10 | .leaflet-shadow-pane,
11 | .leaflet-marker-pane,
12 | .leaflet-popup-pane,
13 | .leaflet-overlay-pane svg,
14 | .leaflet-zoom-box,
15 | .leaflet-image-layer,
16 | .leaflet-layer {
17 | position: absolute;
18 | left: 0;
19 | top: 0;
20 | }
21 | .leaflet-container {
22 | overflow: hidden;
23 | -ms-touch-action: none;
24 | }
25 | .leaflet-tile,
26 | .leaflet-marker-icon,
27 | .leaflet-marker-shadow {
28 | -webkit-user-select: none;
29 | -moz-user-select: none;
30 | user-select: none;
31 | -webkit-user-drag: none;
32 | }
33 | .leaflet-marker-icon,
34 | .leaflet-marker-shadow {
35 | display: block;
36 | }
37 | /* map is broken in FF if you have max-width: 100% on tiles */
38 | .leaflet-container img {
39 | max-width: none !important;
40 | }
41 | /* stupid Android 2 doesn't understand "max-width: none" properly */
42 | .leaflet-container img.leaflet-image-layer {
43 | max-width: 15000px !important;
44 | }
45 | .leaflet-tile {
46 | filter: inherit;
47 | visibility: hidden;
48 | }
49 | .leaflet-tile-loaded {
50 | visibility: inherit;
51 | }
52 | .leaflet-zoom-box {
53 | width: 0;
54 | height: 0;
55 | }
56 | /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
57 | .leaflet-overlay-pane svg {
58 | -moz-user-select: none;
59 | }
60 |
61 | .leaflet-tile-pane { z-index: 2; }
62 | .leaflet-objects-pane { z-index: 3; }
63 | .leaflet-overlay-pane { z-index: 4; }
64 | .leaflet-shadow-pane { z-index: 5; }
65 | .leaflet-marker-pane { z-index: 6; }
66 | .leaflet-popup-pane { z-index: 7; }
67 |
68 |
69 | /* control positioning */
70 |
71 | .leaflet-control {
72 | position: relative;
73 | z-index: 7;
74 | pointer-events: auto;
75 | }
76 | .leaflet-top,
77 | .leaflet-bottom {
78 | position: absolute;
79 | z-index: 1000;
80 | pointer-events: none;
81 | }
82 | .leaflet-top {
83 | top: 0;
84 | }
85 | .leaflet-right {
86 | right: 0;
87 | }
88 | .leaflet-bottom {
89 | bottom: 0;
90 | }
91 | .leaflet-left {
92 | left: 0;
93 | }
94 | .leaflet-control {
95 | float: left;
96 | clear: both;
97 | }
98 | .leaflet-right .leaflet-control {
99 | float: right;
100 | }
101 | .leaflet-top .leaflet-control {
102 | margin-top: 10px;
103 | }
104 | .leaflet-bottom .leaflet-control {
105 | margin-bottom: 10px;
106 | }
107 | .leaflet-left .leaflet-control {
108 | margin-left: 10px;
109 | }
110 | .leaflet-right .leaflet-control {
111 | margin-right: 10px;
112 | }
113 |
114 |
115 | /* zoom and fade animations */
116 |
117 | .leaflet-fade-anim .leaflet-tile,
118 | .leaflet-fade-anim .leaflet-popup {
119 | opacity: 0;
120 | -webkit-transition: opacity 0.2s linear;
121 | -moz-transition: opacity 0.2s linear;
122 | -o-transition: opacity 0.2s linear;
123 | transition: opacity 0.2s linear;
124 | }
125 | .leaflet-fade-anim .leaflet-tile-loaded,
126 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
127 | opacity: 1;
128 | }
129 |
130 | .leaflet-zoom-anim .leaflet-zoom-animated {
131 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
132 | -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
133 | -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
134 | transition: transform 0.25s cubic-bezier(0,0,0.25,1);
135 | }
136 | .leaflet-zoom-anim .leaflet-tile,
137 | .leaflet-pan-anim .leaflet-tile,
138 | .leaflet-touching .leaflet-zoom-animated {
139 | -webkit-transition: none;
140 | -moz-transition: none;
141 | -o-transition: none;
142 | transition: none;
143 | }
144 |
145 | .leaflet-zoom-anim .leaflet-zoom-hide {
146 | visibility: hidden;
147 | }
148 |
149 |
150 | /* cursors */
151 |
152 | .leaflet-clickable {
153 | cursor: pointer;
154 | }
155 | .leaflet-container {
156 | cursor: -webkit-grab;
157 | cursor: -moz-grab;
158 | }
159 | .leaflet-popup-pane,
160 | .leaflet-control {
161 | cursor: auto;
162 | }
163 | .leaflet-dragging,
164 | .leaflet-dragging .leaflet-clickable,
165 | .leaflet-dragging .leaflet-container {
166 | cursor: move;
167 | cursor: -webkit-grabbing;
168 | cursor: -moz-grabbing;
169 | }
170 |
171 |
172 | /* visual tweaks */
173 |
174 | .leaflet-container {
175 | background: #ddd;
176 | outline: 0;
177 | }
178 | .leaflet-container a {
179 | color: #0078A8;
180 | }
181 | .leaflet-container a.leaflet-active {
182 | outline: 2px solid orange;
183 | }
184 | .leaflet-zoom-box {
185 | border: 2px dotted #05f;
186 | background: white;
187 | opacity: 0.5;
188 | }
189 |
190 |
191 | /* general typography */
192 | .leaflet-container {
193 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
194 | }
195 |
196 |
197 | /* general toolbar styles */
198 |
199 | .leaflet-bar {
200 | box-shadow: 0 1px 7px rgba(0,0,0,0.65);
201 | -webkit-border-radius: 4px;
202 | border-radius: 4px;
203 | }
204 | .leaflet-bar a, .leaflet-bar a:hover {
205 | background-color: #fff;
206 | border-bottom: 1px solid #ccc;
207 | width: 26px;
208 | height: 26px;
209 | line-height: 26px;
210 | display: block;
211 | text-align: center;
212 | text-decoration: none;
213 | color: black;
214 | }
215 | .leaflet-bar a,
216 | .leaflet-control-layers-toggle {
217 | background-position: 50% 50%;
218 | background-repeat: no-repeat;
219 | display: block;
220 | }
221 | .leaflet-bar a:hover {
222 | background-color: #f4f4f4;
223 | }
224 | .leaflet-bar a:first-child {
225 | -webkit-border-top-left-radius: 4px;
226 | border-top-left-radius: 4px;
227 | -webkit-border-top-right-radius: 4px;
228 | border-top-right-radius: 4px;
229 | }
230 | .leaflet-bar a:last-child {
231 | -webkit-border-bottom-left-radius: 4px;
232 | border-bottom-left-radius: 4px;
233 | -webkit-border-bottom-right-radius: 4px;
234 | border-bottom-right-radius: 4px;
235 | border-bottom: none;
236 | }
237 | .leaflet-bar a.leaflet-disabled {
238 | cursor: default;
239 | background-color: #f4f4f4;
240 | color: #bbb;
241 | }
242 |
243 | .leaflet-touch .leaflet-bar {
244 | -webkit-border-radius: 10px;
245 | border-radius: 10px;
246 | }
247 | .leaflet-touch .leaflet-bar a {
248 | width: 30px;
249 | height: 30px;
250 | }
251 | .leaflet-touch .leaflet-bar a:first-child {
252 | -webkit-border-top-left-radius: 7px;
253 | border-top-left-radius: 7px;
254 | -webkit-border-top-right-radius: 7px;
255 | border-top-right-radius: 7px;
256 | }
257 | .leaflet-touch .leaflet-bar a:last-child {
258 | -webkit-border-bottom-left-radius: 7px;
259 | border-bottom-left-radius: 7px;
260 | -webkit-border-bottom-right-radius: 7px;
261 | border-bottom-right-radius: 7px;
262 | border-bottom: none;
263 | }
264 |
265 |
266 | /* zoom control */
267 |
268 | .leaflet-control-zoom-in {
269 | font: bold 18px 'Lucida Console', Monaco, monospace;
270 | }
271 | .leaflet-control-zoom-out {
272 | font: bold 22px 'Lucida Console', Monaco, monospace;
273 | }
274 |
275 | .leaflet-touch .leaflet-control-zoom-in {
276 | font-size: 22px;
277 | line-height: 30px;
278 | }
279 | .leaflet-touch .leaflet-control-zoom-out {
280 | font-size: 28px;
281 | line-height: 30px;
282 | }
283 |
284 |
285 | /* layers control */
286 |
287 | .leaflet-control-layers {
288 | box-shadow: 0 1px 7px rgba(0,0,0,0.4);
289 | background: #f8f8f9;
290 | -webkit-border-radius: 5px;
291 | border-radius: 5px;
292 | }
293 | .leaflet-control-layers-toggle {
294 | background-image: url(images/layers.png);
295 | width: 36px;
296 | height: 36px;
297 | }
298 | .leaflet-retina .leaflet-control-layers-toggle {
299 | background-image: url(images/layers-2x.png);
300 | background-size: 26px 26px;
301 | }
302 | .leaflet-touch .leaflet-control-layers-toggle {
303 | width: 44px;
304 | height: 44px;
305 | }
306 | .leaflet-control-layers .leaflet-control-layers-list,
307 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle {
308 | display: none;
309 | }
310 | .leaflet-control-layers-expanded .leaflet-control-layers-list {
311 | display: block;
312 | position: relative;
313 | }
314 | .leaflet-control-layers-expanded {
315 | padding: 6px 10px 6px 6px;
316 | color: #333;
317 | background: #fff;
318 | }
319 | .leaflet-control-layers-selector {
320 | margin-top: 2px;
321 | position: relative;
322 | top: 1px;
323 | }
324 | .leaflet-control-layers label {
325 | display: block;
326 | }
327 | .leaflet-control-layers-separator {
328 | height: 0;
329 | border-top: 1px solid #ddd;
330 | margin: 5px -10px 5px -6px;
331 | }
332 |
333 |
334 | /* attribution and scale controls */
335 |
336 | .leaflet-container .leaflet-control-attribution {
337 | background-color: rgba(255, 255, 255, 0.7);
338 | box-shadow: 0 0 5px #bbb;
339 | margin: 0;
340 | }
341 | .leaflet-control-attribution,
342 | .leaflet-control-scale-line {
343 | padding: 0 5px;
344 | color: #333;
345 | }
346 | .leaflet-container .leaflet-control-attribution,
347 | .leaflet-container .leaflet-control-scale {
348 | font-size: 11px;
349 | }
350 | .leaflet-left .leaflet-control-scale {
351 | margin-left: 5px;
352 | }
353 | .leaflet-bottom .leaflet-control-scale {
354 | margin-bottom: 5px;
355 | }
356 | .leaflet-control-scale-line {
357 | border: 2px solid #777;
358 | border-top: none;
359 | color: black;
360 | line-height: 1.1;
361 | padding: 2px 5px 1px;
362 | font-size: 11px;
363 | text-shadow: 1px 1px 1px #fff;
364 | background-color: rgba(255, 255, 255, 0.5);
365 | box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2);
366 | white-space: nowrap;
367 | overflow: hidden;
368 | }
369 | .leaflet-control-scale-line:not(:first-child) {
370 | border-top: 2px solid #777;
371 | border-bottom: none;
372 | margin-top: -2px;
373 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
374 | }
375 | .leaflet-control-scale-line:not(:first-child):not(:last-child) {
376 | border-bottom: 2px solid #777;
377 | }
378 |
379 | .leaflet-touch .leaflet-control-attribution,
380 | .leaflet-touch .leaflet-control-layers,
381 | .leaflet-touch .leaflet-bar {
382 | box-shadow: none;
383 | }
384 | .leaflet-touch .leaflet-control-layers,
385 | .leaflet-touch .leaflet-bar {
386 | border: 4px solid rgba(0,0,0,0.3);
387 | }
388 |
389 |
390 | /* popup */
391 |
392 | .leaflet-popup {
393 | position: absolute;
394 | text-align: center;
395 | }
396 | .leaflet-popup-content-wrapper {
397 | padding: 1px;
398 | text-align: left;
399 | -webkit-border-radius: 12px;
400 | border-radius: 12px;
401 | }
402 | .leaflet-popup-content {
403 | margin: 13px 19px;
404 | line-height: 1.4;
405 | }
406 | .leaflet-popup-content p {
407 | margin: 18px 0;
408 | }
409 | .leaflet-popup-tip-container {
410 | margin: 0 auto;
411 | width: 40px;
412 | height: 20px;
413 | position: relative;
414 | overflow: hidden;
415 | }
416 | .leaflet-popup-tip {
417 | width: 17px;
418 | height: 17px;
419 | padding: 1px;
420 |
421 | margin: -10px auto 0;
422 |
423 | -webkit-transform: rotate(45deg);
424 | -moz-transform: rotate(45deg);
425 | -ms-transform: rotate(45deg);
426 | -o-transform: rotate(45deg);
427 | transform: rotate(45deg);
428 | }
429 | .leaflet-popup-content-wrapper, .leaflet-popup-tip {
430 | background: white;
431 |
432 | box-shadow: 0 3px 14px rgba(0,0,0,0.4);
433 | }
434 | .leaflet-container a.leaflet-popup-close-button {
435 | position: absolute;
436 | top: 0;
437 | right: 0;
438 | padding: 4px 4px 0 0;
439 | text-align: center;
440 | width: 18px;
441 | height: 14px;
442 | font: 16px/14px Tahoma, Verdana, sans-serif;
443 | color: #c3c3c3;
444 | text-decoration: none;
445 | font-weight: bold;
446 | background: transparent;
447 | }
448 | .leaflet-container a.leaflet-popup-close-button:hover {
449 | color: #999;
450 | }
451 | .leaflet-popup-scrolled {
452 | overflow: auto;
453 | border-bottom: 1px solid #ddd;
454 | border-top: 1px solid #ddd;
455 | }
456 |
457 |
458 | /* div icon */
459 |
460 | .leaflet-div-icon {
461 | background: #fff;
462 | border: 1px solid #666;
463 | }
464 | .leaflet-editing-icon {
465 | -webkit-border-radius: 2px;
466 | border-radius: 2px;
467 | }
468 |
--------------------------------------------------------------------------------
/oabutton/static/public/css/bootstrap-theme.min.css:
--------------------------------------------------------------------------------
1 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,0%,#e6e6e6,100%);background-image:-moz-linear-gradient(top,#fff 0,#e6e6e6 100%);background-image:linear-gradient(to bottom,#fff 0,#e6e6e6 100%);background-repeat:repeat-x;border-color:#e0e0e0;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0)}.btn-default:active,.btn-default.active{background-color:#e6e6e6;border-color:#e0e0e0}.btn-primary{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca,0%,#3071a9,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;border-color:#2d6ca2;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.btn-primary:active,.btn-primary.active{background-color:#3071a9;border-color:#2d6ca2}.btn-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c,0%,#449d44,100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;border-color:#419641;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.btn-success:active,.btn-success.active{background-color:#449d44;border-color:#419641}.btn-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e,0%,#ec971f,100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;border-color:#eb9316;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.btn-warning:active,.btn-warning.active{background-color:#ec971f;border-color:#eb9316}.btn-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f,0%,#c9302c,100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;border-color:#c12e2a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.btn-danger:active,.btn-danger.active{background-color:#c9302c;border-color:#c12e2a}.btn-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de,0%,#31b0d5,100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;border-color:#2aabd2;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.btn-info:active,.btn-info.active{background-color:#31b0d5;border-color:#2aabd2}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca,0%,#357ebd,100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#f8f8f8));background-image:-webkit-linear-gradient(top,#fff,0%,#f8f8f8,100%);background-image:-moz-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar .navbar-nav>.active>a{background-color:#f8f8f8}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-gradient(linear,left 0,left 100%,from(#3c3c3c),to(#222));background-image:-webkit-linear-gradient(top,#3c3c3c,0%,#222,100%);background-image:-moz-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0)}.navbar-inverse .navbar-nav>.active>a{background-color:#222}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#c8e5bc));background-image:-webkit-linear-gradient(top,#dff0d8,0%,#c8e5bc,100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#b9def0));background-image:-webkit-linear-gradient(top,#d9edf7,0%,#b9def0,100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#f8efc0));background-image:-webkit-linear-gradient(top,#fcf8e3,0%,#f8efc0,100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#e7c3c3));background-image:-webkit-linear-gradient(top,#f2dede,0%,#e7c3c3,100%);background-image:-moz-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#ebebeb,0%,#f5f5f5,100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca,0%,#3071a9,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c,0%,#449d44,100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de,0%,#31b0d5,100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e,0%,#ec971f,100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f,0%,#c9302c,100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3278b3));background-image:-webkit-linear-gradient(top,#428bca,0%,#3278b3,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5,0%,#e8e8e8,100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca,0%,#357ebd,100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#d0e9c6));background-image:-webkit-linear-gradient(top,#dff0d8,0%,#d0e9c6,100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#c4e3f3));background-image:-webkit-linear-gradient(top,#d9edf7,0%,#c4e3f3,100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#faf2cc));background-image:-webkit-linear-gradient(top,#fcf8e3,0%,#faf2cc,100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#ebcccc));background-image:-webkit-linear-gradient(top,#f2dede,0%,#ebcccc,100%);background-image:-moz-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-gradient(linear,left 0,left 100%,from(#e8e8e8),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#e8e8e8,0%,#f5f5f5,100%);background-image:-moz-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)}
--------------------------------------------------------------------------------