├── .gitignore ├── Dockerfile ├── LICENSE ├── Readme.md ├── accounts ├── __init__.py ├── backends.py ├── forms │ ├── __init__.py │ ├── authenticate.py │ └── register.py ├── logging │ ├── __init__.py │ └── signals.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── templates │ ├── base_accounts.html │ ├── login.html │ └── register.html ├── tests.py ├── urls.py └── views.py ├── annotationsets ├── __init__.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20150818_0905.py │ └── __init__.py ├── models.py └── tests.py ├── api ├── __init__.py ├── authentication.py ├── serializers.py ├── tests.py ├── urls.py ├── views.py └── viewsets.py ├── common ├── __init__.py ├── annotation.py ├── exceptions.py ├── knowledge │ ├── __init__.py │ ├── provider.py │ ├── tests.py │ └── wikidata │ │ ├── __init__.py │ │ ├── config.py │ │ ├── provider.py │ │ ├── wd_download.py │ │ ├── wd_extract.py │ │ └── wd_import.py ├── mixins.py ├── sparql.py ├── statements.py ├── tests.py ├── uri.py └── vocab.py ├── docker-compose.yml ├── documents ├── __init__.py ├── logging │ ├── __init__.py │ └── signals.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── tests.py ├── urls.py └── views.py ├── elasticsearch └── wikidata │ └── person.json.bz2 ├── endpoint ├── __init__.py ├── tests.py ├── urls.py └── views.py ├── fixtures ├── accounts.json ├── annotationsets.json └── documents.json ├── manage.py ├── mapping.json ├── neonion ├── __init__.py ├── processors.py ├── static │ ├── bootstrap │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── js │ │ │ ├── .jscsrc │ │ │ ├── .jshintrc │ │ │ ├── affix.js │ │ │ ├── alert.js │ │ │ ├── button.js │ │ │ ├── carousel.js │ │ │ ├── collapse.js │ │ │ ├── dropdown.js │ │ │ ├── modal.js │ │ │ ├── popover.js │ │ │ ├── scrollspy.js │ │ │ ├── tab.js │ │ │ ├── tests │ │ │ │ ├── README.md │ │ │ │ ├── index.html │ │ │ │ ├── unit │ │ │ │ │ ├── .jshintrc │ │ │ │ │ ├── affix.js │ │ │ │ │ ├── alert.js │ │ │ │ │ ├── button.js │ │ │ │ │ ├── carousel.js │ │ │ │ │ ├── collapse.js │ │ │ │ │ ├── dropdown.js │ │ │ │ │ ├── modal.js │ │ │ │ │ ├── phantom.js │ │ │ │ │ ├── popover.js │ │ │ │ │ ├── scrollspy.js │ │ │ │ │ ├── tab.js │ │ │ │ │ └── tooltip.js │ │ │ │ ├── vendor │ │ │ │ │ ├── jquery.min.js │ │ │ │ │ ├── qunit.css │ │ │ │ │ └── qunit.js │ │ │ │ └── visual │ │ │ │ │ ├── affix-with-sticky-footer.html │ │ │ │ │ ├── affix.html │ │ │ │ │ ├── alert.html │ │ │ │ │ ├── button.html │ │ │ │ │ ├── carousel.html │ │ │ │ │ ├── collapse.html │ │ │ │ │ ├── dropdown.html │ │ │ │ │ ├── modal.html │ │ │ │ │ ├── popover.html │ │ │ │ │ ├── scrollspy.html │ │ │ │ │ ├── tab.html │ │ │ │ │ └── tooltip.html │ │ │ ├── tooltip.js │ │ │ └── transition.js │ │ └── less │ │ │ ├── .csscomb.json │ │ │ ├── .csslintrc │ │ │ ├── alerts.less │ │ │ ├── badges.less │ │ │ ├── bootstrap.less │ │ │ ├── breadcrumbs.less │ │ │ ├── button-groups.less │ │ │ ├── buttons.less │ │ │ ├── carousel.less │ │ │ ├── close.less │ │ │ ├── code.less │ │ │ ├── component-animations.less │ │ │ ├── dropdowns.less │ │ │ ├── forms.less │ │ │ ├── glyphicons.less │ │ │ ├── grid.less │ │ │ ├── input-groups.less │ │ │ ├── jumbotron.less │ │ │ ├── labels.less │ │ │ ├── list-group.less │ │ │ ├── media.less │ │ │ ├── mixins.less │ │ │ ├── mixins │ │ │ ├── alerts.less │ │ │ ├── background-variant.less │ │ │ ├── border-radius.less │ │ │ ├── buttons.less │ │ │ ├── center-block.less │ │ │ ├── clearfix.less │ │ │ ├── forms.less │ │ │ ├── gradients.less │ │ │ ├── grid-framework.less │ │ │ ├── grid.less │ │ │ ├── hide-text.less │ │ │ ├── image.less │ │ │ ├── labels.less │ │ │ ├── list-group.less │ │ │ ├── nav-divider.less │ │ │ ├── nav-vertical-align.less │ │ │ ├── opacity.less │ │ │ ├── pagination.less │ │ │ ├── panels.less │ │ │ ├── progress-bar.less │ │ │ ├── reset-filter.less │ │ │ ├── reset-text.less │ │ │ ├── resize.less │ │ │ ├── responsive-visibility.less │ │ │ ├── size.less │ │ │ ├── tab-focus.less │ │ │ ├── table-row.less │ │ │ ├── text-emphasis.less │ │ │ ├── text-overflow.less │ │ │ └── vendor-prefixes.less │ │ │ ├── modals.less │ │ │ ├── navbar.less │ │ │ ├── navs.less │ │ │ ├── normalize.less │ │ │ ├── pager.less │ │ │ ├── pagination.less │ │ │ ├── panels.less │ │ │ ├── popovers.less │ │ │ ├── print.less │ │ │ ├── progress-bars.less │ │ │ ├── responsive-embed.less │ │ │ ├── responsive-utilities.less │ │ │ ├── scaffolding.less │ │ │ ├── tables.less │ │ │ ├── theme.less │ │ │ ├── thumbnails.less │ │ │ ├── tooltip.less │ │ │ ├── type.less │ │ │ ├── utilities.less │ │ │ ├── variables.less │ │ │ └── wells.less │ ├── favicon.ico │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── Lato │ │ │ ├── Lato-Bold-latin-ext.woff2 │ │ │ ├── Lato-Bold-latin.woff2 │ │ │ ├── Lato-Bold.woff │ │ │ ├── Lato-Light-latin-ext.woff2 │ │ │ ├── Lato-Light-latin.woff2 │ │ │ ├── Lato-Light.woff │ │ │ ├── Lato-Regular-latin-ext.woff2 │ │ │ ├── Lato-Regular-latin.woff2 │ │ │ └── Lato-Regular.woff │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── gulpfile.js │ ├── img │ │ ├── annotator-glyph-sprite.png │ │ ├── annotator-icon-sprite.png │ │ ├── annotator │ │ │ ├── relation_checkmark_black.svg │ │ │ ├── relation_checkmark_white.svg │ │ │ ├── relation_create.svg │ │ │ ├── relation_edit.svg │ │ │ ├── relation_remove_black.svg │ │ │ └── relation_remove_white.svg │ │ ├── logo.png │ │ └── unknown.png │ ├── js │ │ ├── angular │ │ │ ├── app.js │ │ │ ├── components.js │ │ │ ├── controllers │ │ │ │ ├── accounts │ │ │ │ │ ├── group-list.js │ │ │ │ │ └── user-list.js │ │ │ │ ├── analyze │ │ │ │ │ └── query.js │ │ │ │ ├── annotations │ │ │ │ │ ├── annotation-list.js │ │ │ │ │ └── occurrence-list.js │ │ │ │ ├── annotator │ │ │ │ │ ├── annotator-context.js │ │ │ │ │ ├── annotator-nav.js │ │ │ │ │ ├── annotator-render-pdf.js │ │ │ │ │ └── annotator.js │ │ │ │ ├── common │ │ │ │ │ └── main.js │ │ │ │ ├── settings │ │ │ │ │ └── metadata.js │ │ │ │ ├── vocabulary │ │ │ │ │ ├── concept-detail.js │ │ │ │ │ ├── concept-list.js │ │ │ │ │ ├── conceptset-detail.js │ │ │ │ │ ├── conceptset-list.js │ │ │ │ │ ├── property-detail.js │ │ │ │ │ └── property-list.js │ │ │ │ ├── workbench │ │ │ │ │ ├── bulk-upload.js │ │ │ │ │ └── orphaned-annotation-list.js │ │ │ │ └── workspace │ │ │ │ │ └── workspace.js │ │ │ ├── filters.js │ │ │ ├── lib │ │ │ │ ├── angular-cookies.js │ │ │ │ ├── angular-cookies.min.js │ │ │ │ ├── angular-cookies.min.js.map │ │ │ │ ├── angular-filter.min.js │ │ │ │ ├── angular-mocks.js │ │ │ │ ├── angular-resource.js │ │ │ │ ├── angular-resource.min.js │ │ │ │ ├── angular-resource.min.js.map │ │ │ │ ├── angular.js │ │ │ │ ├── angular.min.js │ │ │ │ ├── angular.min.js.map │ │ │ │ ├── ng-file-upload-shim.min.js │ │ │ │ └── ng-file-upload.min.js │ │ │ ├── root.js │ │ │ └── services │ │ │ │ ├── annotation-store.js │ │ │ │ ├── annotator.js │ │ │ │ ├── common.js │ │ │ │ ├── concept.js │ │ │ │ ├── conceptset.js │ │ │ │ ├── document.js │ │ │ │ ├── group.js │ │ │ │ ├── linked-concept.js │ │ │ │ ├── membership.js │ │ │ │ ├── property.js │ │ │ │ ├── user.js │ │ │ │ └── workspace.js │ │ ├── annotator │ │ │ ├── annotator.min.js │ │ │ ├── annotator.neonion.extensions.js │ │ │ ├── annotator.neonion.extensions.relation.extraction.js │ │ │ ├── annotator.neonion.extensions.relations.js │ │ │ ├── annotator.neonion.js │ │ │ ├── annotator.ner.js │ │ │ └── annotator.store.min.js │ │ ├── bootstrap.min.js │ │ ├── jquery-ui.min.js │ │ ├── jquery.min.js │ │ ├── neonion-context.jsonld │ │ ├── pdf │ │ │ ├── pdf.js │ │ │ ├── pdf.worker.js │ │ │ ├── text_layer_builder.js │ │ │ └── ui_utils.js │ │ └── sgvizler.min.js │ ├── less │ │ ├── custom-bootstrap.less │ │ ├── custom-variables.less │ │ ├── modules │ │ │ ├── colors.less │ │ │ └── variables.less │ │ ├── my-bootstrap-theme.less │ │ ├── partials │ │ │ ├── annotator.neonion.less │ │ │ ├── base.less │ │ │ ├── buttons.less │ │ │ ├── font.less │ │ │ ├── helper.less │ │ │ └── links.less │ │ ├── styleguide.md │ │ └── vendor │ │ │ ├── annotator.less │ │ │ └── font-awesome.min.less │ ├── main.css │ ├── partials │ │ ├── accounts-group-list.html │ │ ├── accounts-user-list.html │ │ ├── analyze-query.html │ │ ├── annotation-list.html │ │ ├── annotations │ │ │ ├── annotation-document-list.html │ │ │ ├── annotation-occurrence-list.html │ │ │ ├── comment-list.html │ │ │ ├── concept-list.html │ │ │ └── highlight-list.html │ │ ├── annotator │ │ │ ├── annotator-context.html │ │ │ ├── annotator-navigation.html │ │ │ └── annotator.html │ │ ├── generic-resource-list.html │ │ ├── import-meta-data.html │ │ ├── meta_data_in_properties.html │ │ ├── vocabulary │ │ │ ├── concept-detail.html │ │ │ ├── conceptset-detail.html │ │ │ ├── multiselect.html │ │ │ └── property-detail.html │ │ ├── workbench │ │ │ ├── elasticsearch.html │ │ │ └── orphaned-annotation-list.html │ │ └── workspace-document-list.html │ └── utils │ │ ├── additional.less │ │ └── styleguide.scss ├── templates │ ├── accounts_management.html │ ├── annotator.html │ ├── base.html │ ├── base_annotations.html │ ├── base_annotations_documents.html │ ├── base_annotations_occurrences.html │ ├── base_import.html │ ├── base_modify.html │ ├── base_settings.html │ ├── base_vocabulary.html │ ├── navigation.html │ ├── query.html │ ├── workbench.html │ └── workspace.html ├── templatetags │ ├── __init__.py │ └── custom_filters.py ├── tests.py ├── urls.py └── views.py ├── requirements.txt ├── settings ├── __init__.py ├── default.py ├── demo.py ├── development.py ├── docker.py ├── production.py └── test.py ├── store ├── __init__.py ├── decorators.py ├── logging │ ├── __init__.py │ └── annotatorLogger.py ├── urls.py └── views.py ├── wikidata ├── __init__.py ├── models.py ├── static │ └── js │ │ └── annotator │ │ └── annotator.neonion.wikidata.js ├── urls.py ├── views.py └── wiki.py ├── wsgi_demo.py ├── wsgi_dev.py ├── wsgi_production.py └── wsgi_test.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | venv 3 | *.pyc 4 | *.pyo 5 | db.* 6 | db.sqlite3 7 | staticfiles 8 | __pycache__ 9 | *.log 10 | /logs 11 | /plugins/*/* 12 | !plugins/__init__.py 13 | *.*~ 14 | 15 | # styleguide 16 | /node_modules 17 | /neonion/static/styleguide 18 | 19 | # converage.py files 20 | .coverage 21 | /htmlcov 22 | 23 | # ignore bash scrips 24 | *.sh 25 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | RUN apt-get -y update 4 | RUN apt-get -y upgrade 5 | RUN apt-get -y install python2.7 python2.7-dev python-pip 6 | RUN apt-get -y install ruby 7 | RUN gem install sass 8 | 9 | # RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 10 | 11 | ENV BASEDIR /src 12 | ENV CODEDIR $BASEDIR/code 13 | ENV STATICFILES $CODEDIR/neonion/static/ 14 | 15 | COPY . $CODEDIR 16 | # bugfix for hardcoded urls 17 | COPY settings/docker.py $CODEDIR/settings/development.py 18 | 19 | # install requirements 20 | RUN /usr/bin/pip install -r ${CODEDIR}/requirements.txt 21 | 22 | # build css 23 | RUN /usr/local/bin/sass $STATICFILES/stylesheets/main.scss $STATICFILES/css/main.css 24 | 25 | # init djang 26 | WORKDIR $CODEDIR 27 | RUN /usr/bin/python manage.py syncdb --noinput 28 | RUN /usr/bin/python manage.py loaddata fixtures/*.json 29 | 30 | RUN /usr/bin/python manage.py collectstatic --noinput 31 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # neonion 2 | 3 | neonion is a user-centered, web application for the collaborative annotation of texts developed at the [Human-Centered Computing group](https://www.mi.fu-berlin.de/inf/groups/hcc/) at Freie Universität Berlin. 4 | 5 | neonion supports semantic annotations and open standards but does not presuppose any knowledge about the technologies involved. It is the perfect fit for people who want their annotations to be exchangeable between different tools and projects. Moreover, your annotations can be connected to the linked data cloud. 6 | 7 | You can [try a demo](https://demo.neonion.imp.fu-berlin.de) of neonion. The usage is explained in the [user's manual](http://fub-hcc.github.io/neonion/). 8 | 9 | 10 | ## Prerequisites 11 | 12 | For neonion you need Python with Django installed. 13 | In addition, a set of tools and services is needed: 14 | 15 | * [Python](https://www.python.org) (Python 2 >=2.7) with `pip` and `virtualenv` 16 | * [ElasticSearch](https://www.elastic.co) (>=5.x) 17 | * **Optional** 18 | * [Sesame](http://rdf4j.org) (>=2.7) 19 | 20 | If you want to use ports other than the default ports you can change the environment settings under `settings/`. 21 | 22 | ## Getting started 23 | 24 | Create a virtualenv and install the dependencies for neonion: 25 | 26 | ``` 27 | virtualenv -p /usr/bin/python2.7 pyenv 28 | source pyenv/bin/activate 29 | pip install -r neonion/requirements.txt 30 | ``` 31 | 32 | Setup neonion and startup the server: 33 | 34 | ``` 35 | source pyenv/bin/activate 36 | cd neonion 37 | curl -XPUT -H'Content-Type: application/json' 'http://127.0.0.1:9200/neonion/' -d @mapping.json 38 | python manage.py migrate 39 | python manage.py loaddata fixtures/* 40 | python manage.py runserver 41 | ``` 42 | You should now see something like: 43 | 44 | ``` 45 | Django version 1.7, using settings 'settings.development' 46 | Starting development server at http://127.0.0.1:8000/ 47 | ``` 48 | Open your browser and navigate to [http://127.0.0.1:8000](http://127.0.0.1:8000). 49 | By default there are two predefined accounts `neonion-admin@fu-berlin.de` and `neonion-test@fu-berlin.de`. Both have the default password `neonion` but different rights. 50 | 51 | ## Import the knowledge base from Wikidata 52 | 53 | When neonion is running you can import the provided person data with: 54 | 55 | ``` 56 | source pyenv/bin/activate 57 | cd neonion 58 | python common/knowledge/wikidata/wd_import.py -f elasticsearch/wikidata/ 59 | ``` 60 | ## License 61 | 62 | GPL2: [http://www.gnu.org/licenses/gpl-2.0.html](http://www.gnu.org/licenses/gpl-2.0.html) 63 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- 1 | import logging.signals 2 | -------------------------------------------------------------------------------- /accounts/backends.py: -------------------------------------------------------------------------------- 1 | from accounts.models import User 2 | 3 | 4 | class EmailAuthBackend(object): 5 | """ 6 | A custom authentication backend. Allows users to log in using their email address. 7 | """ 8 | 9 | def authenticate(self, username=None, password=None): 10 | """ 11 | Authentication method 12 | """ 13 | try: 14 | user = User.objects.get(username=username) 15 | if user.check_password(password): 16 | return user 17 | except User.DoesNotExist: 18 | return None 19 | 20 | def get_user(self, user_id): 21 | try: 22 | user = User.objects.get(pk=user_id) 23 | if user.is_active: 24 | return user 25 | return None 26 | except User.DoesNotExist: 27 | return None 28 | -------------------------------------------------------------------------------- /accounts/forms/__init__.py: -------------------------------------------------------------------------------- 1 | from .register import RegistrationForm 2 | from .authenticate import AuthenticationForm -------------------------------------------------------------------------------- /accounts/forms/authenticate.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib.auth import authenticate 3 | 4 | 5 | class AuthenticationForm(forms.Form): 6 | """ 7 | Login form 8 | """ 9 | username = forms.CharField(label='User', 10 | max_length=80, 11 | widget=forms.TextInput( 12 | attrs={'class': 'form-control', 'data-h5-errorid': 'invalid_username', 'required': ''})) 13 | 14 | password = forms.CharField(label='Password', 15 | widget=forms.PasswordInput(attrs={'class': 'form-control', 'required': ''})) 16 | 17 | def clean(self): 18 | # print( self.cleaned_data ) 19 | username = self.cleaned_data.get('username') 20 | password = self.cleaned_data.get('password') 21 | 22 | user = authenticate(username=username, password=password) 23 | if not user: 24 | raise forms.ValidationError("Sorry, that login was invalid. Please try again.") 25 | elif not user.is_active: 26 | raise forms.ValidationError("An administrator must approve this request before you can login.") 27 | return self.cleaned_data 28 | 29 | class Meta: 30 | fields = ['username', 'password'] 31 | -------------------------------------------------------------------------------- /accounts/forms/register.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from accounts.models import User 3 | 4 | 5 | class RegistrationForm(forms.ModelForm): 6 | """ 7 | Form for registering a new account. 8 | """ 9 | 10 | email = forms.EmailField(label='Email', 11 | max_length=80, 12 | widget=forms.TextInput( 13 | attrs={'class': 'form-control', 'data-h5-errorid': 'invalid_email', 'required': ''})) 14 | 15 | password = forms.CharField(label='Password', 16 | widget=forms.PasswordInput(attrs={'class': 'form-control', 'required': ''})) 17 | 18 | class Meta: 19 | model = User 20 | fields = ['email', 'password'] 21 | 22 | def clean(self): 23 | cleaned_data = super(RegistrationForm, self).clean() 24 | mail = cleaned_data.get('email', '') 25 | password = cleaned_data.get('password', '') 26 | 27 | return self.cleaned_data 28 | 29 | def save(self, commit=True): 30 | user = super(RegistrationForm, self).save(commit=False) 31 | user.username = user.email 32 | user.set_password(self.cleaned_data['password']) 33 | if commit: 34 | user.save() 35 | return user 36 | -------------------------------------------------------------------------------- /accounts/logging/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/accounts/logging/__init__.py -------------------------------------------------------------------------------- /accounts/logging/signals.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from accounts.models import User 3 | from django.dispatch import receiver 4 | from django.db.models.signals import post_save 5 | from django.conf import settings 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | 10 | @receiver(post_save, sender=User) 11 | def user_created(sender, instance, created, **kwargs): 12 | if settings.USER_LOGGING_ENABLED: 13 | if created: 14 | email = instance.email 15 | logger.info('user_created=' + email) 16 | else: 17 | email = instance.email 18 | logger.info('user_signedin=' + email) 19 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /accounts/templates/base_accounts.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block content %} 6 | {% block registration %} 7 | {% endblock %} 8 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base_accounts.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Sign In{% endblock %} 6 | {% block page_id %}signin{% endblock %} 7 | 8 | {% block registration %} 9 |
10 |
11 |
12 | {% csrf_token %} 13 |
14 |

Please Sign In before using neonion.

15 |
16 | 17 | {{ form.username }} 18 | {% for error in form.username.errors %} 19 |
{{ error|escape }}
20 | {% endfor %} 21 |
22 |
23 | 24 | {{ form.password }} 25 |
26 |
27 | 28 | 29 |
30 |
31 |
32 | 33 | {% for error in form.non_field_errors %} 34 | 37 | {% endfor %} 38 |
39 |
40 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends "base_accounts.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Sign Up{% endblock %} 6 | {% block page_id %}signup{% endblock %} 7 | 8 | {% block registration %} 9 |
10 |
11 |
12 | {% csrf_token %} 13 |
14 |

You need to register in order to use neonion.

15 | 16 |
17 | 18 | {{ form.email }} 19 | {% for error in form.email.errors %} 20 |
{{ error|escape }}
21 | {% endfor %} 22 |
23 |
24 | 25 | {{ form.password }} 26 | {% for error in form.password.errors %} 27 |
{{ error|escape }}
28 | {% endfor %} 29 |
30 |
31 | 32 | 33 |
34 |
35 |
36 | 37 | {% if success %} 38 | {% if show_activation_info %} 39 | 40 | {% else %} 41 | 42 | {% endif %} 43 | {% endif %} 44 |
45 |
46 | {% endblock %} 47 | -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url 2 | 3 | urlpatterns = [ 4 | url(r'^register/?$', 'accounts.views.register'), 5 | url(r'^login/?$', 'accounts.views.login'), 6 | url(r'^logout/?$', 'accounts.views.logout'), 7 | ] 8 | -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.shortcuts import render_to_response, redirect 3 | from django.template import RequestContext 4 | from django.contrib.auth import login as django_login, authenticate, logout as django_logout 5 | from accounts.forms import AuthenticationForm, RegistrationForm 6 | 7 | 8 | def login(request): 9 | """ 10 | Login view 11 | """ 12 | if request.method == 'POST': 13 | form = AuthenticationForm(data=request.POST) 14 | if form.is_valid(): 15 | user = authenticate(username=request.POST['username'], password=request.POST['password']) 16 | if user is not None: 17 | if user.is_active: 18 | django_login(request, user) 19 | return redirect('/') 20 | else: 21 | form = AuthenticationForm() 22 | 23 | return render_to_response('login.html', { 24 | 'form': form, 25 | }, context_instance=RequestContext(request)) 26 | 27 | 28 | def register(request): 29 | """ 30 | User registration view. 31 | """ 32 | if 'accounts.backends.EmailAuthBackend' in settings.AUTHENTICATION_BACKENDS: 33 | success = False 34 | show_activation_info = False 35 | if request.method == 'POST': 36 | form = RegistrationForm(data=request.POST) 37 | if form.is_valid(): 38 | user = form.save() 39 | success = True 40 | show_activation_info = not user.is_active 41 | else: 42 | form = RegistrationForm() 43 | 44 | return render_to_response('register.html', { 45 | 'form': form, 'success': success, 'show_activation_info': show_activation_info 46 | }, context_instance=RequestContext(request)) 47 | else: 48 | return redirect('accounts.views.login') 49 | 50 | 51 | def logout(request): 52 | """ 53 | Log out view 54 | """ 55 | django_logout(request) 56 | return redirect('accounts.views.login') -------------------------------------------------------------------------------- /annotationsets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/annotationsets/__init__.py -------------------------------------------------------------------------------- /annotationsets/migrations/0002_auto_20150818_0905.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('annotationsets', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='linkedconcept', 16 | name='custom_query', 17 | field=models.CharField(max_length=500, null=True, blank=True), 18 | preserve_default=True, 19 | ), 20 | migrations.AddField( 21 | model_name='linkedconcept', 22 | name='retrieved_at', 23 | field=models.DateTimeField(null=True, blank=True), 24 | preserve_default=True, 25 | ), 26 | migrations.AlterField( 27 | model_name='linkedconcept', 28 | name='provider_class', 29 | field=models.CharField(max_length=100, null=True, verbose_name=b'provider_class', blank=True), 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /annotationsets/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/annotationsets/migrations/__init__.py -------------------------------------------------------------------------------- /annotationsets/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from common.vocab import neonion 3 | from common.mixins import ResourceMixin 4 | 5 | 6 | class LinkedProperty(ResourceMixin, models.Model): 7 | # URI to the property in then external ontology 8 | linked_property = models.URLField('linked_property', blank=False, max_length=300) 9 | 10 | class_uri = neonion.LINKED_PROPERTY 11 | 12 | class Meta: 13 | app_label = "annotationsets" 14 | 15 | 16 | class Property(ResourceMixin, models.Model): 17 | range = models.ManyToManyField("Concept", blank=True) 18 | # inverse property is the property to the inverse direction 19 | inverse_property = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL) 20 | # list of linked properties 21 | linked_properties = models.ManyToManyField("LinkedProperty", blank=True) 22 | 23 | class_uri = neonion.PROPERTY 24 | 25 | class Meta: 26 | app_label = "annotationsets" 27 | 28 | 29 | 30 | class LinkedConcept(ResourceMixin, models.Model): 31 | endpoint = models.URLField('endpoint', null=True, blank=True, max_length=300) 32 | # URI to the concept in then external ontology 33 | linked_type = models.URLField('linked_type', blank=False, max_length=300) 34 | # path to the class which implements the knowledge extraction provider 35 | provider_class = models.CharField('provider_class', null=True, blank=True, max_length=100) 36 | custom_query = models.CharField(null=True, blank=True, max_length=500) 37 | retrieved_at = models.DateTimeField(null=True, blank=True) 38 | 39 | class_uri = neonion.LINKED_CONCEPT 40 | 41 | class Meta: 42 | app_label = "annotationsets" 43 | 44 | 45 | 46 | class Concept(ResourceMixin, models.Model): 47 | # list of resource provider to external knowledge 48 | linked_concepts = models.ManyToManyField("LinkedConcept", blank=True) 49 | properties = models.ManyToManyField("Property", blank=True) 50 | 51 | class_uri = neonion.CONCEPT 52 | 53 | class Meta: 54 | app_label = "annotationsets" 55 | 56 | 57 | 58 | class ConceptSet(ResourceMixin, models.Model): 59 | # list of concepts associated with set 60 | concepts = models.ManyToManyField("Concept", blank=True) 61 | 62 | class_uri = neonion.CONCEPT_SET 63 | 64 | class Meta: 65 | app_label = "annotationsets" 66 | 67 | 68 | -------------------------------------------------------------------------------- /annotationsets/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from models import ConceptSet, LinkedConcept, Concept 3 | 4 | 5 | class AnnotationSetsTestCase(TestCase): 6 | 7 | def setUp(self): 8 | test_set = { 9 | 'uri': 'http://neonion.org/', 10 | 'label': 'Test Document', 11 | } 12 | self.annotation_set = ConceptSet.objects.create(**test_set) -------------------------------------------------------------------------------- /api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/api/__init__.py -------------------------------------------------------------------------------- /api/authentication.py: -------------------------------------------------------------------------------- 1 | from rest_framework.authentication import BaseAuthentication 2 | 3 | 4 | class UnsafeSessionAuthentication(BaseAuthentication): 5 | """ 6 | Use Django's session framework for authentication. 7 | """ 8 | 9 | def authenticate(self, request): 10 | """ 11 | Returns a `User` if the request session currently has a logged in user. 12 | Otherwise returns `None`. 13 | """ 14 | 15 | # Get the underlying HttpRequest object 16 | request = request._request 17 | user = getattr(request, 'user', None) 18 | 19 | # Unauthenticated, CSRF validation not required 20 | if not user or not user.is_active: 21 | return None 22 | 23 | return (user, None) 24 | -------------------------------------------------------------------------------- /api/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from accounts.tests import create_test_user 3 | from documents.tests import create_test_document 4 | 5 | 6 | class DocumentAPITestCase(TestCase): 7 | 8 | def setUp(self): 9 | # create test user 10 | self.test_user = create_test_user() 11 | 12 | # create test document 13 | self.test_document = create_test_document() 14 | 15 | def test_get_documents(self): 16 | self.assertTrue(self.client.login(email='test@neonin.org', password='tester')) 17 | response = self.client.get('/api/documents') 18 | self.assertTrue(len(response.data) == 1) 19 | 20 | def test_get_document(self): 21 | self.assertTrue(self.client.login(email='test@neonin.org', password='tester')) 22 | 23 | response = self.client.get('/api/documents/' + self.test_document.id) 24 | self.assertDictContainsSubset({'id': self.test_document.id}, response.data) 25 | 26 | 27 | class UserAPITestCase(TestCase): 28 | 29 | def setUp(self): 30 | # create test user 31 | self.test_user = create_test_user() 32 | 33 | def test_current_user(self): 34 | self.assertTrue(self.client.login(email='test@neonin.org', password='tester')) 35 | 36 | response = self.client.get('/api/users/current') 37 | self.assertDictContainsSubset({'email': self.test_user.email}, response.data) 38 | 39 | 40 | class WorkingGroupAPITestCase(TestCase): 41 | 42 | def setUp(self): 43 | # create test user 44 | self.test_user = create_test_user() -------------------------------------------------------------------------------- /api/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url, include 2 | from rest_framework import routers 3 | from viewsets import UserViewSet, WorkingGroupViewSet, DocumentViewSet, ConceptSetViewSet, ConceptViewSet, \ 4 | PropertyViewSet, LinkedConceptViewSet, MembershipViewSet 5 | 6 | # Routers provide an easy way of automatically determining the URL conf. 7 | router = routers.DefaultRouter(trailing_slash=False) 8 | router.register(r'users', UserViewSet) 9 | router.register(r'memberships', MembershipViewSet) 10 | router.register(r'groups', WorkingGroupViewSet) 11 | router.register(r'documents', DocumentViewSet) 12 | router.register(r'conceptsets', ConceptSetViewSet) 13 | router.register(r'concepts', ConceptViewSet) 14 | router.register(r'linkedconcepts', LinkedConceptViewSet) 15 | router.register(r'properties', PropertyViewSet) 16 | 17 | urlpatterns = [ 18 | url(r'^', include(router.urls)), 19 | 20 | # ElasticSearch proxy 21 | url(r'^es/search/(?P.+)/(?P.+)/(?P.+)$', 'api.views.entity_search'), 22 | url(r'^es/import/(?P.+)/(?P.+)$', 'api.views.entity_bulk_import'), 23 | ] 24 | -------------------------------------------------------------------------------- /api/views.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from django.conf import settings 4 | from django.contrib.auth.decorators import login_required 5 | from django.http import HttpResponse 6 | from django.http import JsonResponse 7 | from django.views.decorators.http import require_GET, require_POST 8 | from elasticsearch import Elasticsearch, TransportError, helpers 9 | from elasticsearch.helpers import BulkIndexError 10 | 11 | from common.knowledge.provider import Provider 12 | 13 | 14 | @login_required 15 | @require_POST 16 | def entity_bulk_import(request, index, type): 17 | json_data = '' 18 | # read chunks 19 | f = request.FILES.getlist('file')[0] 20 | for chunk in f.chunks(): 21 | json_data += chunk 22 | 23 | data = json.loads(json_data) 24 | 25 | es = Elasticsearch(settings.ELASTICSEARCH_URL) 26 | try: 27 | es.indices.create(index) 28 | except TransportError: 29 | pass 30 | 31 | # clear item of type in document 32 | try: 33 | es.delete_by_query(index=index, doc_type=type, body='{"query":{"match_all":{}}}') 34 | except Exception: 35 | pass 36 | 37 | # https://gist.github.com/jayswan/a8d9920ef74516a02fe1 38 | # create generator 39 | def items(): 40 | for item in data: 41 | item['_type'] = type 42 | item['_index'] = index 43 | yield item 44 | 45 | try: 46 | helpers.bulk(es, items()) 47 | except BulkIndexError: 48 | pass 49 | 50 | # refresh the index 51 | es.indices.refresh(index=index) 52 | 53 | return HttpResponse(status=201) 54 | 55 | 56 | @login_required 57 | @require_GET 58 | def entity_search(request, index, type, term): 59 | # call search method from provider 60 | provider = Provider(settings.ELASTICSEARCH_URL) 61 | return JsonResponse(provider.search(term, type, index), safe=False) 62 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/common/__init__.py -------------------------------------------------------------------------------- /common/exceptions.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class InvalidAnnotationError(Exception): 4 | 5 | def __init__(self, message, code=None, params=None): 6 | super(InvalidAnnotationError, self).__init__(message, code, params) 7 | 8 | def __str__(self): 9 | if hasattr(self, 'error_dict'): 10 | return repr(dict(self)) 11 | return repr(list(self)) 12 | 13 | def __repr__(self): 14 | return 'InvalidAnnotationError(%s)' % self 15 | 16 | 17 | class InvalidResourceTypeError(Exception): 18 | 19 | def __init__(self, value): 20 | self.value = value 21 | 22 | def __str__(self): 23 | return repr(self.value) 24 | -------------------------------------------------------------------------------- /common/knowledge/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/common/knowledge/__init__.py -------------------------------------------------------------------------------- /common/knowledge/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from provider import Provider 3 | 4 | 5 | class ProviderTestCase(TestCase): 6 | 7 | def setUp(self): 8 | pass -------------------------------------------------------------------------------- /common/knowledge/wikidata/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/common/knowledge/wikidata/__init__.py -------------------------------------------------------------------------------- /common/knowledge/wikidata/config.py: -------------------------------------------------------------------------------- 1 | WIKIDATA_DUMPS_URL = 'https://dumps.wikimedia.org/other/wikidata/{}' 2 | ELASTICSEARCH_URL = 'http://localhost:9200/' 3 | LANGUAGES = ['en','de'] -------------------------------------------------------------------------------- /common/mixins.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.conf import settings 3 | 4 | 5 | class ResourceMixin(models.Model): 6 | id = models.CharField('id', primary_key=True, max_length=50) 7 | label = models.CharField('label', max_length=100) 8 | comment = models.CharField('comment', blank=True, max_length=500) 9 | 10 | class Meta: 11 | abstract = True 12 | 13 | def uri(self): 14 | class_name = self.__class__.__name__.lower() 15 | return settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/' + class_name + '/' + self.id 16 | 17 | def __str__(self): 18 | return self.label 19 | -------------------------------------------------------------------------------- /common/sparql.py: -------------------------------------------------------------------------------- 1 | from SPARQLWrapper import SPARQLWrapper 2 | from django.conf import settings 3 | 4 | 5 | def prepare_sparql(format='json'): 6 | if hasattr(settings, 'ENDPOINT') and hasattr(settings, 'ENDPOINT_UPDATE'): 7 | sparql = SPARQLWrapper(settings.ENDPOINT, settings.ENDPOINT_UPDATE) 8 | sparql.method = 'GET' 9 | sparql.setReturnFormat(format) 10 | return sparql 11 | else: 12 | raise ValueError("Missing parameter for ENDPOINT") 13 | 14 | 15 | def insert_data(query): 16 | if query: 17 | sparql = prepare_sparql() 18 | sparql.method = 'POST' 19 | sparql.setQuery(query) 20 | return sparql.query() 21 | 22 | 23 | def execute_query(query, format='json'): 24 | if query: 25 | sparql = prepare_sparql(format) 26 | sparql.setQuery(query) 27 | return sparql.query().convert() -------------------------------------------------------------------------------- /common/uri.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | from django.conf import settings 4 | from django.core.validators import URLValidator 5 | from django.core.exceptions import ValidationError 6 | from common.exceptions import InvalidResourceTypeError 7 | 8 | 9 | def generate_uri(resource_type, name=None): 10 | validate = URLValidator() 11 | try: 12 | validate(resource_type) 13 | 14 | if name is None: 15 | # generate random uuid 16 | resource_id = uuid.uuid1().hex 17 | else: 18 | # generate uuid from provided name 19 | resource_id = uuid.uuid5(uuid.NAMESPACE_URL, name.lower().encode('utf8', 'replace')).hex 20 | 21 | concept_name = resource_type.rstrip('/').rsplit('/', 1)[1] 22 | return '{}/{}/{}'.format( 23 | settings.NEONION_BASE_NAMESPACE.rstrip('/'), 24 | concept_name, 25 | resource_id 26 | ) 27 | except ValidationError: 28 | raise InvalidResourceTypeError(resource_type) 29 | 30 | 31 | def generate_urn(name=None): 32 | if name is None: 33 | # generate random uuid 34 | resource_uuid = uuid.uuid1().hex 35 | else: 36 | # generate uuid from provided name 37 | resource_uuid = uuid.uuid5(uuid.NAMESPACE_URL, name.lower().encode('utf8', 'replace')).hex 38 | 39 | return 'urn:uuid:{}'.format(resource_uuid) 40 | -------------------------------------------------------------------------------- /common/vocab.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from enum import Enum 3 | 4 | 5 | class neonion: 6 | USER = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/ontology/user' 7 | ANNOTATION = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/ontology/annotation' 8 | CONCEPT_SET = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/ontology/conceptset' 9 | CONCEPT = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/ontology/concept' 10 | LINKED_CONCEPT = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/ontology/linkedconcept' 11 | PROPERTY = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/ontology/property' 12 | LINKED_PROPERTY = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/ontology/linkedproperty' 13 | DOCUMENT = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/ontology/document' 14 | 15 | ANNOTATION_STORE_GRAPH = settings.NEONION_BASE_NAMESPACE.rstrip('/') + '/annotationStore' 16 | 17 | 18 | class OpenAnnotation: 19 | PREFIX = 'oa:' 20 | 21 | class DocumentTypes(Enum): 22 | text = 'dctypes:Text' 23 | 24 | class TagTypes(Enum): 25 | tag = 'oa:Tag' 26 | semanticTag = 'oa:SemanticTag' 27 | 28 | class Motivations(Enum): 29 | commenting = 'oa:commenting' 30 | highlighting = 'oa:highlighting' 31 | tagging = 'oa:tagging' 32 | classifying = 'oa:classifying' 33 | identifying = 'oa:identifying' 34 | linking = 'oa:linking' 35 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | web: 2 | build: . 3 | command: python manage.py runserver 0.0.0.0:8000 4 | links: 5 | - elasticsearch 6 | volumes: 7 | - ./data:/data 8 | ports: 9 | - "8000:8000" 10 | 11 | elasticsearch: 12 | image: elasticsearch 13 | ports: 14 | - "9200:9200" -------------------------------------------------------------------------------- /documents/__init__.py: -------------------------------------------------------------------------------- 1 | import logging.signals 2 | -------------------------------------------------------------------------------- /documents/logging/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/documents/logging/__init__.py -------------------------------------------------------------------------------- /documents/logging/signals.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import logging 3 | from documents.models import Document 4 | from django.dispatch import receiver 5 | from django.db.models.signals import post_save 6 | from django.conf import settings 7 | 8 | 9 | log = logging.getLogger(__name__) 10 | 11 | 12 | # Signal which ensures that metadata gets saved automatically after newly created document 13 | @receiver(post_save, sender=Document) 14 | def document_created(sender, instance, created, **kwargs): 15 | if settings.USER_LOGGING_ENABLED: 16 | if created: 17 | try: 18 | title = instance.title 19 | creator = instance.description 20 | log.info('document_created=_%s'%(title)) 21 | except Exception as e: 22 | print(e.message) 23 | 24 | def log_document_metadata_request_error(error): 25 | #if settings.USER_LOGGING_ENABLED: 26 | log.error(error) 27 | -------------------------------------------------------------------------------- /documents/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/documents/migrations/__init__.py -------------------------------------------------------------------------------- /documents/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from models import Document 3 | 4 | 5 | def create_test_document(doc_id='12345'): 6 | test_document = { 7 | 'id': doc_id, 8 | 'title': 'Test Document', 9 | 'type': 'Article', 10 | 'creator': 'test@nutzer.com' 11 | } 12 | return Document.objects.create(**test_document) 13 | 14 | 15 | class DocumentsTestCase(TestCase): 16 | 17 | def setUp(self): 18 | self.test_document = create_test_document() -------------------------------------------------------------------------------- /documents/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | urlpatterns = [ 4 | url(r'^upload$', 'documents.views.upload_file'), 5 | url(r'^(?P.+)/modify$', 'documents.views.modify_document'), 6 | url(r'^search_metadata/(?P.+)$', 'documents.views.search_metadata'), 7 | url(r'^viewer/(?P<pk>.+)$', 'documents.views.viewer'), 8 | ] 9 | -------------------------------------------------------------------------------- /elasticsearch/wikidata/person.json.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/elasticsearch/wikidata/person.json.bz2 -------------------------------------------------------------------------------- /endpoint/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/endpoint/__init__.py -------------------------------------------------------------------------------- /endpoint/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /endpoint/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | urlpatterns = [ 4 | url(r'^query$', 'endpoint.views.query'), 5 | ] -------------------------------------------------------------------------------- /endpoint/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.decorators import login_required 2 | from django.views.decorators.http import require_http_methods 3 | from common.sparql import execute_query 4 | from django.http import HttpResponseForbidden, JsonResponse 5 | 6 | 7 | @login_required 8 | @require_http_methods(["GET", "POST"]) 9 | def query(request): 10 | sparql_query = '' 11 | sparql_output = 'json' 12 | 13 | if request.method == 'POST': 14 | sparql_query = request.POST.get('query') 15 | sparql_output = request.POST.get('output') 16 | elif request.method == 'GET': 17 | if 'query' in request.GET: sparql_query = request.GET['query'] 18 | if 'output' in request.GET: sparql_output = request.GET['output'] 19 | 20 | try: 21 | print(request.POST) 22 | # execute query 23 | return JsonResponse(execute_query(sparql_query, sparql_output)) 24 | except Exception as e: 25 | return HttpResponseForbidden() 26 | -------------------------------------------------------------------------------- /fixtures/accounts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "fields": { 4 | "comment": "", 5 | "owner": 1, 6 | "documents": [ 7 | "4e41bee6c28111e4b236c42c0303b893", 8 | "688cea47c27f11e494e4c42c0303b893", 9 | "ba07e20ac28311e4a5bec42c0303b893", 10 | "ac93538cc28a11e4b948c42c0303b893" 11 | ], 12 | "name": "Public" 13 | }, 14 | "model": "accounts.workinggroup", 15 | "pk": 1 16 | }, 17 | { 18 | "fields": { 19 | "surname": "", 20 | "name": "", 21 | "is_active": true, 22 | "joined": "2014-12-22T14:12:01.868Z", 23 | "last_login": "2014-12-22T14:12:01.743Z", 24 | "is_superuser": false, 25 | "password": "pbkdf2_sha256$12000$ETvI760YU3He$C76eiXw2X8p8OibaZUkXNmKFa0z23MedwveNZC6xivA=", 26 | "email": "neonion-test@fu-berlin.de", 27 | "username": "neonion-test@fu-berlin.de" 28 | }, 29 | "model": "accounts.user", 30 | "pk": 1 31 | }, 32 | { 33 | "fields": { 34 | "surname": "", 35 | "name": "", 36 | "is_active": true, 37 | "joined": "2014-12-22T14:12:17.516Z", 38 | "last_login": "2014-12-22T14:12:17.402Z", 39 | "is_superuser": true, 40 | "password": "pbkdf2_sha256$12000$TG8p0bASUBWu$0VvZ5qoawys5kyFogTxRDy4pn33Vv4V/Xot//X9MraU=", 41 | "email": "neonion-admin@fu-berlin.de", 42 | "username": "neonion-admin@fu-berlin.de", 43 | "owned_documents": [ 44 | "ac93538cc28a11e4b948c42c0303b893" 45 | ] 46 | }, 47 | "model": "accounts.user", 48 | "pk": 2 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | 7 | # set production environment 8 | #os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.production") 9 | 10 | # set development environment 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.development") 12 | 13 | # set test environment 14 | #os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.test") 15 | 16 | from django.core.management import execute_from_command_line 17 | 18 | execute_from_command_line(sys.argv) 19 | -------------------------------------------------------------------------------- /neonion/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/__init__.py -------------------------------------------------------------------------------- /neonion/processors.py: -------------------------------------------------------------------------------- 1 | def system_settings(request): 2 | from django.conf import settings 3 | 4 | return { 5 | 'system': { 6 | 'services': { 7 | 'user_logging': { 8 | 'kibana_url': settings.KIBANA_URL, 9 | 'enabled': settings.USER_LOGGING_ENABLED, 10 | }, 11 | 'endpoint': { 12 | 'enabled': settings.ENDPOINT_ENABLED, 13 | } 14 | }, 15 | 'annotator': { 16 | 'services': { 17 | 'stanford_ner': { 18 | 'enabled': settings.NER_SERVICE_ENABLED, 19 | 'service_url': settings.NER_SERVICE_URL, 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /neonion/static/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /neonion/static/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /neonion/static/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "disallowEmptyBlocks": true, 3 | "disallowKeywords": ["with"], 4 | "disallowMixedSpacesAndTabs": true, 5 | "disallowMultipleLineStrings": true, 6 | "disallowMultipleVarDecl": true, 7 | "disallowQuotedKeysInObjects": "allButReserved", 8 | "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"], 9 | "disallowSpaceBeforeBinaryOperators": [","], 10 | "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"], 11 | "disallowSpacesInFunctionDeclaration": { "beforeOpeningRoundBrace": true }, 12 | "disallowSpacesInNamedFunctionExpression": { "beforeOpeningRoundBrace": true }, 13 | "disallowSpacesInsideArrayBrackets": true, 14 | "disallowSpacesInsideParentheses": true, 15 | "disallowTrailingComma": true, 16 | "disallowTrailingWhitespace": true, 17 | "requireCamelCaseOrUpperCaseIdentifiers": true, 18 | "requireCapitalizedConstructors": true, 19 | "requireCommaBeforeLineBreak": true, 20 | "requireDollarBeforejQueryAssignment": true, 21 | "requireDotNotation": true, 22 | "requireLineFeedAtFileEnd": true, 23 | "requirePaddingNewLinesAfterUseStrict": true, 24 | "requirePaddingNewLinesBeforeExport": true, 25 | "requireSpaceAfterBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", "<", ">=", "<="], 26 | "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"], 27 | "requireSpaceAfterLineComment": true, 28 | "requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", "<", ">=", "<="], 29 | "requireSpaceBetweenArguments": true, 30 | "requireSpacesInAnonymousFunctionExpression": { "beforeOpeningCurlyBrace": true, "beforeOpeningRoundBrace": true }, 31 | "requireSpacesInConditionalExpression": true, 32 | "requireSpacesInForStatement": true, 33 | "requireSpacesInFunctionDeclaration": { "beforeOpeningCurlyBrace": true }, 34 | "requireSpacesInFunctionExpression": { "beforeOpeningCurlyBrace": true }, 35 | "requireSpacesInNamedFunctionExpression": { "beforeOpeningCurlyBrace": true }, 36 | "requireSpacesInsideObjectBrackets": "allButNested", 37 | "validateAlignedFunctionParameters": true, 38 | "validateIndentation": 2, 39 | "validateLineBreaks": "LF", 40 | "validateNewlineAfterArrayElements": true, 41 | "validateQuoteMarks": "'" 42 | } 43 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi" : true, 3 | "browser" : true, 4 | "eqeqeq" : false, 5 | "eqnull" : true, 6 | "es3" : true, 7 | "expr" : true, 8 | "jquery" : true, 9 | "latedef" : true, 10 | "laxbreak" : true, 11 | "nonbsp" : true, 12 | "strict" : true, 13 | "undef" : true, 14 | "unused" : true 15 | } 16 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/alert.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: alert.js v3.3.5 3 | * http://getbootstrap.com/javascript/#alerts 4 | * ======================================================================== 5 | * Copyright 2011-2015 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // ALERT CLASS DEFINITION 14 | // ====================== 15 | 16 | var dismiss = '[data-dismiss="alert"]' 17 | var Alert = function (el) { 18 | $(el).on('click', dismiss, this.close) 19 | } 20 | 21 | Alert.VERSION = '3.3.5' 22 | 23 | Alert.TRANSITION_DURATION = 150 24 | 25 | Alert.prototype.close = function (e) { 26 | var $this = $(this) 27 | var selector = $this.attr('data-target') 28 | 29 | if (!selector) { 30 | selector = $this.attr('href') 31 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 32 | } 33 | 34 | var $parent = $(selector) 35 | 36 | if (e) e.preventDefault() 37 | 38 | if (!$parent.length) { 39 | $parent = $this.closest('.alert') 40 | } 41 | 42 | $parent.trigger(e = $.Event('close.bs.alert')) 43 | 44 | if (e.isDefaultPrevented()) return 45 | 46 | $parent.removeClass('in') 47 | 48 | function removeElement() { 49 | // detach from parent, fire event then clean up data 50 | $parent.detach().trigger('closed.bs.alert').remove() 51 | } 52 | 53 | $.support.transition && $parent.hasClass('fade') ? 54 | $parent 55 | .one('bsTransitionEnd', removeElement) 56 | .emulateTransitionEnd(Alert.TRANSITION_DURATION) : 57 | removeElement() 58 | } 59 | 60 | 61 | // ALERT PLUGIN DEFINITION 62 | // ======================= 63 | 64 | function Plugin(option) { 65 | return this.each(function () { 66 | var $this = $(this) 67 | var data = $this.data('bs.alert') 68 | 69 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 70 | if (typeof option == 'string') data[option].call($this) 71 | }) 72 | } 73 | 74 | var old = $.fn.alert 75 | 76 | $.fn.alert = Plugin 77 | $.fn.alert.Constructor = Alert 78 | 79 | 80 | // ALERT NO CONFLICT 81 | // ================= 82 | 83 | $.fn.alert.noConflict = function () { 84 | $.fn.alert = old 85 | return this 86 | } 87 | 88 | 89 | // ALERT DATA-API 90 | // ============== 91 | 92 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 93 | 94 | }(jQuery); 95 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/tests/unit/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends" : "../../.jshintrc", 3 | "devel" : true, 4 | "es3" : false, 5 | "qunit" : true 6 | } 7 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/tests/unit/phantom.js: -------------------------------------------------------------------------------- 1 | /* 2 | * grunt-contrib-qunit 3 | * http://gruntjs.com/ 4 | * 5 | * Copyright (c) 2014 "Cowboy" Ben Alman, contributors 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | (function () { 10 | 'use strict'; 11 | 12 | // Don't re-order tests. 13 | QUnit.config.reorder = false 14 | // Run tests serially, not in parallel. 15 | QUnit.config.autorun = false 16 | 17 | // Send messages to the parent PhantomJS process via alert! Good times!! 18 | function sendMessage() { 19 | var args = [].slice.call(arguments) 20 | alert(JSON.stringify(args)) 21 | } 22 | 23 | // These methods connect QUnit to PhantomJS. 24 | QUnit.log(function (obj) { 25 | // What is this I don’t even 26 | if (obj.message === '[object Object], undefined:undefined') { return } 27 | 28 | // Parse some stuff before sending it. 29 | var actual 30 | var expected 31 | if (!obj.result) { 32 | // Dumping large objects can be very slow, and the dump isn't used for 33 | // passing tests, so only dump if the test failed. 34 | actual = QUnit.dump.parse(obj.actual) 35 | expected = QUnit.dump.parse(obj.expected) 36 | } 37 | // Send it. 38 | sendMessage('qunit.log', obj.result, actual, expected, obj.message, obj.source) 39 | }) 40 | 41 | QUnit.testStart(function (obj) { 42 | sendMessage('qunit.testStart', obj.name) 43 | }) 44 | 45 | QUnit.testDone(function (obj) { 46 | sendMessage('qunit.testDone', obj.name, obj.failed, obj.passed, obj.total, obj.duration) 47 | }) 48 | 49 | QUnit.moduleStart(function (obj) { 50 | sendMessage('qunit.moduleStart', obj.name) 51 | }) 52 | 53 | QUnit.moduleDone(function (obj) { 54 | if (obj.failed === 0) { 55 | console.log('\r\u221A All tests passed in "' + obj.name + '" module') 56 | } else { 57 | console.log('\u00D7 ' + obj.failed + ' tests failed in "' + obj.name + '" module') 58 | } 59 | sendMessage('qunit.moduleDone', obj.name, obj.failed, obj.passed, obj.total) 60 | }) 61 | 62 | QUnit.begin(function () { 63 | sendMessage('qunit.begin') 64 | console.log('\n\nStarting test suite') 65 | console.log('================================================\n') 66 | }) 67 | 68 | QUnit.done(function (obj) { 69 | sendMessage('qunit.done', obj.failed, obj.passed, obj.total, obj.runtime) 70 | }) 71 | 72 | }()) 73 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/tests/visual/alert.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head> 4 | <meta charset="utf-8"> 5 | <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 | <meta name="viewport" content="width=device-width, initial-scale=1"> 7 | <title>Alert 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 |
20 | 21 | 24 | 25 |
26 | 27 | Holy guacamole! Best check yo self, you're not looking too good. 28 |
29 | 30 |
31 | 32 |

Oh snap! You got an error!

33 |

Change this and that and try again. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum.

34 |

35 | 36 | 37 |

38 |
39 | 40 |
41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/tests/visual/button.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Button 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 |
20 | 21 | 24 | 25 | 28 | 29 | 30 | 31 |
32 | 35 | 38 | 41 |
42 | 43 |
44 | 47 | 50 | 53 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/tests/visual/carousel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Carousel 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 |
20 | 21 | 24 | 25 | 49 | 50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/tests/visual/popover.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Popover 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 |
20 | 21 | 24 | 25 | 28 | 31 | 34 | 37 | 38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/js/transition.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: transition.js v3.3.5 3 | * http://getbootstrap.com/javascript/#transitions 4 | * ======================================================================== 5 | * Copyright 2011-2015 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 14 | // ============================================================ 15 | 16 | function transitionEnd() { 17 | var el = document.createElement('bootstrap') 18 | 19 | var transEndEventNames = { 20 | WebkitTransition : 'webkitTransitionEnd', 21 | MozTransition : 'transitionend', 22 | OTransition : 'oTransitionEnd otransitionend', 23 | transition : 'transitionend' 24 | } 25 | 26 | for (var name in transEndEventNames) { 27 | if (el.style[name] !== undefined) { 28 | return { end: transEndEventNames[name] } 29 | } 30 | } 31 | 32 | return false // explicit for ie8 ( ._.) 33 | } 34 | 35 | // http://blog.alexmaccaw.com/css-transitions 36 | $.fn.emulateTransitionEnd = function (duration) { 37 | var called = false 38 | var $el = this 39 | $(this).one('bsTransitionEnd', function () { called = true }) 40 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 41 | setTimeout(callback, duration) 42 | return this 43 | } 44 | 45 | $(function () { 46 | $.support.transition = transitionEnd() 47 | 48 | if (!$.support.transition) return 49 | 50 | $.event.special.bsTransitionEnd = { 51 | bindType: $.support.transition.end, 52 | delegateType: $.support.transition.end, 53 | handle: function (e) { 54 | if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 55 | } 56 | } 57 | }) 58 | 59 | }(jQuery); 60 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "adjoining-classes": false, 3 | "box-sizing": false, 4 | "box-model": false, 5 | "compatible-vendor-prefixes": false, 6 | "floats": false, 7 | "font-sizes": false, 8 | "gradients": false, 9 | "important": false, 10 | "known-properties": false, 11 | "outline-none": false, 12 | "qualified-headings": false, 13 | "regex-selectors": false, 14 | "shorthand": false, 15 | "text-indent": false, 16 | "unique-headings": false, 17 | "universal-selector": false, 18 | "unqualified-attributes": false 19 | } 20 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/alerts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Alerts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base styles 7 | // ------------------------- 8 | 9 | .alert { 10 | padding: @alert-padding; 11 | margin-bottom: @line-height-computed; 12 | border: 1px solid transparent; 13 | border-radius: @alert-border-radius; 14 | 15 | // Headings for larger alerts 16 | h4 { 17 | margin-top: 0; 18 | // Specified for the h4 to prevent conflicts of changing @headings-color 19 | color: inherit; 20 | } 21 | 22 | // Provide class for links that match alerts 23 | .alert-link { 24 | font-weight: @alert-link-font-weight; 25 | } 26 | 27 | // Improve alignment and spacing of inner content 28 | > p, 29 | > ul { 30 | margin-bottom: 0; 31 | } 32 | 33 | > p + p { 34 | margin-top: 5px; 35 | } 36 | } 37 | 38 | // Dismissible alerts 39 | // 40 | // Expand the right padding and account for the close button's positioning. 41 | 42 | .alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0. 43 | .alert-dismissible { 44 | padding-right: (@alert-padding + 20); 45 | 46 | // Adjust close link position 47 | .close { 48 | position: relative; 49 | top: -2px; 50 | right: -21px; 51 | color: inherit; 52 | } 53 | } 54 | 55 | // Alternate styles 56 | // 57 | // Generate contextual modifier classes for colorizing the alert. 58 | 59 | .alert-success { 60 | .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text); 61 | } 62 | 63 | .alert-info { 64 | .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text); 65 | } 66 | 67 | .alert-warning { 68 | .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text); 69 | } 70 | 71 | .alert-danger { 72 | .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text); 73 | } 74 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/badges.less: -------------------------------------------------------------------------------- 1 | // 2 | // Badges 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .badge { 8 | display: inline-block; 9 | min-width: 10px; 10 | padding: 3px 7px; 11 | font-size: @font-size-small; 12 | font-weight: @badge-font-weight; 13 | color: @badge-color; 14 | line-height: @badge-line-height; 15 | vertical-align: middle; 16 | white-space: nowrap; 17 | text-align: center; 18 | background-color: @badge-bg; 19 | border-radius: @badge-border-radius; 20 | 21 | // Empty badges collapse automatically (not available in IE8) 22 | &:empty { 23 | display: none; 24 | } 25 | 26 | // Quick fix for badges in buttons 27 | .btn & { 28 | position: relative; 29 | top: -1px; 30 | } 31 | 32 | .btn-xs &, 33 | .btn-group-xs > .btn & { 34 | top: 0; 35 | padding: 1px 5px; 36 | } 37 | 38 | // Hover state, but only for links 39 | a& { 40 | &:hover, 41 | &:focus { 42 | color: @badge-link-hover-color; 43 | text-decoration: none; 44 | cursor: pointer; 45 | } 46 | } 47 | 48 | // Account for badges in navs 49 | .list-group-item.active > &, 50 | .nav-pills > .active > a > & { 51 | color: @badge-active-color; 52 | background-color: @badge-active-bg; 53 | } 54 | 55 | .list-group-item > & { 56 | float: right; 57 | } 58 | 59 | .list-group-item > & + & { 60 | margin-right: 5px; 61 | } 62 | 63 | .nav-pills > li > a > & { 64 | margin-left: 3px; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/bootstrap.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | // Core variables and mixins 8 | @import "variables.less"; 9 | @import "mixins.less"; 10 | 11 | // Reset and dependencies 12 | @import "normalize.less"; 13 | @import "print.less"; 14 | @import "glyphicons.less"; 15 | 16 | // Core CSS 17 | @import "scaffolding.less"; 18 | @import "type.less"; 19 | @import "code.less"; 20 | @import "grid.less"; 21 | @import "tables.less"; 22 | @import "forms.less"; 23 | @import "buttons.less"; 24 | 25 | // Components 26 | @import "component-animations.less"; 27 | @import "dropdowns.less"; 28 | @import "button-groups.less"; 29 | @import "input-groups.less"; 30 | @import "navs.less"; 31 | @import "navbar.less"; 32 | @import "breadcrumbs.less"; 33 | @import "pagination.less"; 34 | @import "pager.less"; 35 | @import "labels.less"; 36 | @import "badges.less"; 37 | @import "jumbotron.less"; 38 | @import "thumbnails.less"; 39 | @import "alerts.less"; 40 | @import "progress-bars.less"; 41 | @import "media.less"; 42 | @import "list-group.less"; 43 | @import "panels.less"; 44 | @import "responsive-embed.less"; 45 | @import "wells.less"; 46 | @import "close.less"; 47 | 48 | // Components w/ JavaScript 49 | @import "modals.less"; 50 | @import "tooltip.less"; 51 | @import "popovers.less"; 52 | @import "carousel.less"; 53 | 54 | // Utility classes 55 | @import "utilities.less"; 56 | @import "responsive-utilities.less"; 57 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal; 8 | margin-bottom: @line-height-computed; 9 | list-style: none; 10 | background-color: @breadcrumb-bg; 11 | border-radius: @border-radius-base; 12 | 13 | > li { 14 | display: inline-block; 15 | 16 | + li:before { 17 | content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space 18 | padding: 0 5px; 19 | color: @breadcrumb-color; 20 | } 21 | } 22 | 23 | > .active { 24 | color: @breadcrumb-active-color; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/close.less: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | 6 | .close { 7 | float: right; 8 | font-size: (@font-size-base * 1.5); 9 | font-weight: @close-font-weight; 10 | line-height: 1; 11 | color: @close-color; 12 | text-shadow: @close-text-shadow; 13 | .opacity(.2); 14 | 15 | &:hover, 16 | &:focus { 17 | color: @close-color; 18 | text-decoration: none; 19 | cursor: pointer; 20 | .opacity(.5); 21 | } 22 | 23 | // Additional properties for button version 24 | // iOS requires the button element instead of an anchor tag. 25 | // If you want the anchor version, it requires `href="#"`. 26 | // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile 27 | button& { 28 | padding: 0; 29 | cursor: pointer; 30 | background: transparent; 31 | border: 0; 32 | -webkit-appearance: none; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/code.less: -------------------------------------------------------------------------------- 1 | // 2 | // Code (inline and block) 3 | // -------------------------------------------------- 4 | 5 | 6 | // Inline and block code styles 7 | code, 8 | kbd, 9 | pre, 10 | samp { 11 | font-family: @font-family-monospace; 12 | } 13 | 14 | // Inline code 15 | code { 16 | padding: 2px 4px; 17 | font-size: 90%; 18 | color: @code-color; 19 | background-color: @code-bg; 20 | border-radius: @border-radius-base; 21 | } 22 | 23 | // User input typically entered via keyboard 24 | kbd { 25 | padding: 2px 4px; 26 | font-size: 90%; 27 | color: @kbd-color; 28 | background-color: @kbd-bg; 29 | border-radius: @border-radius-small; 30 | box-shadow: inset 0 -1px 0 rgba(0,0,0,.25); 31 | 32 | kbd { 33 | padding: 0; 34 | font-size: 100%; 35 | font-weight: bold; 36 | box-shadow: none; 37 | } 38 | } 39 | 40 | // Blocks of code 41 | pre { 42 | display: block; 43 | padding: ((@line-height-computed - 1) / 2); 44 | margin: 0 0 (@line-height-computed / 2); 45 | font-size: (@font-size-base - 1); // 14px to 13px 46 | line-height: @line-height-base; 47 | word-break: break-all; 48 | word-wrap: break-word; 49 | color: @pre-color; 50 | background-color: @pre-bg; 51 | border: 1px solid @pre-border-color; 52 | border-radius: @border-radius-base; 53 | 54 | // Account for some code outputs that place code tags in pre tags 55 | code { 56 | padding: 0; 57 | font-size: inherit; 58 | color: inherit; 59 | white-space: pre-wrap; 60 | background-color: transparent; 61 | border-radius: 0; 62 | } 63 | } 64 | 65 | // Enable scrollable blocks of code 66 | .pre-scrollable { 67 | max-height: @pre-scrollable-max-height; 68 | overflow-y: scroll; 69 | } 70 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/component-animations.less: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | // Heads up! 6 | // 7 | // We don't use the `.opacity()` mixin here since it causes a bug with text 8 | // fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552. 9 | 10 | .fade { 11 | opacity: 0; 12 | .transition(opacity .15s linear); 13 | &.in { 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .collapse { 19 | display: none; 20 | 21 | &.in { display: block; } 22 | tr&.in { display: table-row; } 23 | tbody&.in { display: table-row-group; } 24 | } 25 | 26 | .collapsing { 27 | position: relative; 28 | height: 0; 29 | overflow: hidden; 30 | .transition-property(~"height, visibility"); 31 | .transition-duration(.35s); 32 | .transition-timing-function(ease); 33 | } 34 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/grid.less: -------------------------------------------------------------------------------- 1 | // 2 | // Grid system 3 | // -------------------------------------------------- 4 | 5 | 6 | // Container widths 7 | // 8 | // Set the container width, and override it for fixed navbars in media queries. 9 | 10 | .container { 11 | .container-fixed(); 12 | 13 | @media (min-width: @screen-sm-min) { 14 | width: @container-sm; 15 | } 16 | @media (min-width: @screen-md-min) { 17 | width: @container-md; 18 | } 19 | @media (min-width: @screen-lg-min) { 20 | width: @container-lg; 21 | } 22 | } 23 | 24 | 25 | // Fluid container 26 | // 27 | // Utilizes the mixin meant for fixed width containers, but without any defined 28 | // width for fluid, full width layouts. 29 | 30 | .container-fluid { 31 | .container-fixed(); 32 | } 33 | 34 | 35 | // Row 36 | // 37 | // Rows contain and clear the floats of your columns. 38 | 39 | .row { 40 | .make-row(); 41 | } 42 | 43 | 44 | // Columns 45 | // 46 | // Common styles for small and large grid columns 47 | 48 | .make-grid-columns(); 49 | 50 | 51 | // Extra small grid 52 | // 53 | // Columns, offsets, pushes, and pulls for extra small devices like 54 | // smartphones. 55 | 56 | .make-grid(xs); 57 | 58 | 59 | // Small grid 60 | // 61 | // Columns, offsets, pushes, and pulls for the small device range, from phones 62 | // to tablets. 63 | 64 | @media (min-width: @screen-sm-min) { 65 | .make-grid(sm); 66 | } 67 | 68 | 69 | // Medium grid 70 | // 71 | // Columns, offsets, pushes, and pulls for the desktop device range. 72 | 73 | @media (min-width: @screen-md-min) { 74 | .make-grid(md); 75 | } 76 | 77 | 78 | // Large grid 79 | // 80 | // Columns, offsets, pushes, and pulls for the large desktop device range. 81 | 82 | @media (min-width: @screen-lg-min) { 83 | .make-grid(lg); 84 | } 85 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/jumbotron.less: -------------------------------------------------------------------------------- 1 | // 2 | // Jumbotron 3 | // -------------------------------------------------- 4 | 5 | 6 | .jumbotron { 7 | padding-top: @jumbotron-padding; 8 | padding-bottom: @jumbotron-padding; 9 | margin-bottom: @jumbotron-padding; 10 | color: @jumbotron-color; 11 | background-color: @jumbotron-bg; 12 | 13 | h1, 14 | .h1 { 15 | color: @jumbotron-heading-color; 16 | } 17 | 18 | p { 19 | margin-bottom: (@jumbotron-padding / 2); 20 | font-size: @jumbotron-font-size; 21 | font-weight: 200; 22 | } 23 | 24 | > hr { 25 | border-top-color: darken(@jumbotron-bg, 10%); 26 | } 27 | 28 | .container &, 29 | .container-fluid & { 30 | border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container 31 | padding-left: (@grid-gutter-width / 2); 32 | padding-right: (@grid-gutter-width / 2); 33 | } 34 | 35 | .container { 36 | max-width: 100%; 37 | } 38 | 39 | @media screen and (min-width: @screen-sm-min) { 40 | padding-top: (@jumbotron-padding * 1.6); 41 | padding-bottom: (@jumbotron-padding * 1.6); 42 | 43 | .container &, 44 | .container-fluid & { 45 | padding-left: (@jumbotron-padding * 2); 46 | padding-right: (@jumbotron-padding * 2); 47 | } 48 | 49 | h1, 50 | .h1 { 51 | font-size: @jumbotron-heading-font-size; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/labels.less: -------------------------------------------------------------------------------- 1 | // 2 | // Labels 3 | // -------------------------------------------------- 4 | 5 | .label { 6 | display: inline; 7 | padding: .2em .6em .3em; 8 | font-size: 75%; 9 | font-weight: bold; 10 | line-height: 1; 11 | color: @label-color; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | border-radius: .25em; 16 | 17 | // Add hover effects, but only for links 18 | a& { 19 | &:hover, 20 | &:focus { 21 | color: @label-link-hover-color; 22 | text-decoration: none; 23 | cursor: pointer; 24 | } 25 | } 26 | 27 | // Empty labels collapse automatically (not available in IE8) 28 | &:empty { 29 | display: none; 30 | } 31 | 32 | // Quick fix for labels in buttons 33 | .btn & { 34 | position: relative; 35 | top: -1px; 36 | } 37 | } 38 | 39 | // Colors 40 | // Contextual variations (linked labels get darker on :hover) 41 | 42 | .label-default { 43 | .label-variant(@label-default-bg); 44 | } 45 | 46 | .label-primary { 47 | .label-variant(@label-primary-bg); 48 | } 49 | 50 | .label-success { 51 | .label-variant(@label-success-bg); 52 | } 53 | 54 | .label-info { 55 | .label-variant(@label-info-bg); 56 | } 57 | 58 | .label-warning { 59 | .label-variant(@label-warning-bg); 60 | } 61 | 62 | .label-danger { 63 | .label-variant(@label-danger-bg); 64 | } 65 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/media.less: -------------------------------------------------------------------------------- 1 | .media { 2 | // Proper spacing between instances of .media 3 | margin-top: 15px; 4 | 5 | &:first-child { 6 | margin-top: 0; 7 | } 8 | } 9 | 10 | .media, 11 | .media-body { 12 | zoom: 1; 13 | overflow: hidden; 14 | } 15 | 16 | .media-body { 17 | width: 10000px; 18 | } 19 | 20 | .media-object { 21 | display: block; 22 | 23 | // Fix collapse in webkit from max-width: 100% and display: table-cell. 24 | &.img-thumbnail { 25 | max-width: none; 26 | } 27 | } 28 | 29 | .media-right, 30 | .media > .pull-right { 31 | padding-left: 10px; 32 | } 33 | 34 | .media-left, 35 | .media > .pull-left { 36 | padding-right: 10px; 37 | } 38 | 39 | .media-left, 40 | .media-right, 41 | .media-body { 42 | display: table-cell; 43 | vertical-align: top; 44 | } 45 | 46 | .media-middle { 47 | vertical-align: middle; 48 | } 49 | 50 | .media-bottom { 51 | vertical-align: bottom; 52 | } 53 | 54 | // Reset margins on headings for tighter default spacing 55 | .media-heading { 56 | margin-top: 0; 57 | margin-bottom: 5px; 58 | } 59 | 60 | // Media list variation 61 | // 62 | // Undo default ul/ol styles 63 | .media-list { 64 | padding-left: 0; 65 | list-style: none; 66 | } 67 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------------------------------- 3 | 4 | // Utilities 5 | @import "mixins/hide-text.less"; 6 | @import "mixins/opacity.less"; 7 | @import "mixins/image.less"; 8 | @import "mixins/labels.less"; 9 | @import "mixins/reset-filter.less"; 10 | @import "mixins/resize.less"; 11 | @import "mixins/responsive-visibility.less"; 12 | @import "mixins/size.less"; 13 | @import "mixins/tab-focus.less"; 14 | @import "mixins/reset-text.less"; 15 | @import "mixins/text-emphasis.less"; 16 | @import "mixins/text-overflow.less"; 17 | @import "mixins/vendor-prefixes.less"; 18 | 19 | // Components 20 | @import "mixins/alerts.less"; 21 | @import "mixins/buttons.less"; 22 | @import "mixins/panels.less"; 23 | @import "mixins/pagination.less"; 24 | @import "mixins/list-group.less"; 25 | @import "mixins/nav-divider.less"; 26 | @import "mixins/forms.less"; 27 | @import "mixins/progress-bar.less"; 28 | @import "mixins/table-row.less"; 29 | 30 | // Skins 31 | @import "mixins/background-variant.less"; 32 | @import "mixins/border-radius.less"; 33 | @import "mixins/gradients.less"; 34 | 35 | // Layout 36 | @import "mixins/clearfix.less"; 37 | @import "mixins/center-block.less"; 38 | @import "mixins/nav-vertical-align.less"; 39 | @import "mixins/grid-framework.less"; 40 | @import "mixins/grid.less"; 41 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/alerts.less: -------------------------------------------------------------------------------- 1 | // Alerts 2 | 3 | .alert-variant(@background; @border; @text-color) { 4 | background-color: @background; 5 | border-color: @border; 6 | color: @text-color; 7 | 8 | hr { 9 | border-top-color: darken(@border, 5%); 10 | } 11 | .alert-link { 12 | color: darken(@text-color, 10%); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/background-variant.less: -------------------------------------------------------------------------------- 1 | // Contextual backgrounds 2 | 3 | .bg-variant(@color) { 4 | background-color: @color; 5 | a&:hover, 6 | a&:focus { 7 | background-color: darken(@color, 10%); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/border-radius.less: -------------------------------------------------------------------------------- 1 | // Single side border-radius 2 | 3 | .border-top-radius(@radius) { 4 | border-top-right-radius: @radius; 5 | border-top-left-radius: @radius; 6 | } 7 | .border-right-radius(@radius) { 8 | border-bottom-right-radius: @radius; 9 | border-top-right-radius: @radius; 10 | } 11 | .border-bottom-radius(@radius) { 12 | border-bottom-right-radius: @radius; 13 | border-bottom-left-radius: @radius; 14 | } 15 | .border-left-radius(@radius) { 16 | border-bottom-left-radius: @radius; 17 | border-top-left-radius: @radius; 18 | } 19 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/buttons.less: -------------------------------------------------------------------------------- 1 | // Button variants 2 | // 3 | // Easily pump out default styles, as well as :hover, :focus, :active, 4 | // and disabled options for all buttons 5 | 6 | .button-variant(@color; @background; @border) { 7 | color: @color; 8 | background-color: @background; 9 | border-color: @border; 10 | 11 | &:focus, 12 | &.focus { 13 | color: @color; 14 | background-color: darken(@background, 10%); 15 | border-color: darken(@border, 25%); 16 | } 17 | &:hover { 18 | color: @color; 19 | background-color: darken(@background, 10%); 20 | border-color: darken(@border, 12%); 21 | } 22 | &:active, 23 | &.active, 24 | .open > .dropdown-toggle& { 25 | color: @color; 26 | background-color: darken(@background, 10%); 27 | border-color: darken(@border, 12%); 28 | 29 | &:hover, 30 | &:focus, 31 | &.focus { 32 | color: @color; 33 | background-color: darken(@background, 17%); 34 | border-color: darken(@border, 25%); 35 | } 36 | } 37 | &:active, 38 | &.active, 39 | .open > .dropdown-toggle& { 40 | background-image: none; 41 | } 42 | &.disabled, 43 | &[disabled], 44 | fieldset[disabled] & { 45 | &:hover, 46 | &:focus, 47 | &.focus { 48 | background-color: @background; 49 | border-color: @border; 50 | } 51 | } 52 | 53 | .badge { 54 | color: @background; 55 | background-color: @color; 56 | } 57 | } 58 | 59 | // Button sizes 60 | .button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { 61 | padding: @padding-vertical @padding-horizontal; 62 | font-size: @font-size; 63 | line-height: @line-height; 64 | border-radius: @border-radius; 65 | } 66 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/center-block.less: -------------------------------------------------------------------------------- 1 | // Center-align a block level element 2 | 3 | .center-block() { 4 | display: block; 5 | margin-left: auto; 6 | margin-right: auto; 7 | } 8 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/clearfix.less: -------------------------------------------------------------------------------- 1 | // Clearfix 2 | // 3 | // For modern browsers 4 | // 1. The space content is one way to avoid an Opera bug when the 5 | // contenteditable attribute is included anywhere else in the document. 6 | // Otherwise it causes space to appear at the top and bottom of elements 7 | // that are clearfixed. 8 | // 2. The use of `table` rather than `block` is only necessary if using 9 | // `:before` to contain the top-margins of child elements. 10 | // 11 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/ 12 | 13 | .clearfix() { 14 | &:before, 15 | &:after { 16 | content: " "; // 1 17 | display: table; // 2 18 | } 19 | &:after { 20 | clear: both; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/hide-text.less: -------------------------------------------------------------------------------- 1 | // CSS image replacement 2 | // 3 | // Heads up! v3 launched with only `.hide-text()`, but per our pattern for 4 | // mixins being reused as classes with the same name, this doesn't hold up. As 5 | // of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. 6 | // 7 | // Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 8 | 9 | // Deprecated as of v3.0.1 (will be removed in v4) 10 | .hide-text() { 11 | font: ~"0/0" a; 12 | color: transparent; 13 | text-shadow: none; 14 | background-color: transparent; 15 | border: 0; 16 | } 17 | 18 | // New mixin to use as of v3.0.1 19 | .text-hide() { 20 | .hide-text(); 21 | } 22 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/image.less: -------------------------------------------------------------------------------- 1 | // Image Mixins 2 | // - Responsive image 3 | // - Retina image 4 | 5 | 6 | // Responsive image 7 | // 8 | // Keep images from scaling beyond the width of their parents. 9 | .img-responsive(@display: block) { 10 | display: @display; 11 | max-width: 100%; // Part 1: Set a maximum relative to the parent 12 | height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching 13 | } 14 | 15 | 16 | // Retina image 17 | // 18 | // Short retina mixin for setting background-image and -size. Note that the 19 | // spelling of `min--moz-device-pixel-ratio` is intentional. 20 | .img-retina(@file-1x; @file-2x; @width-1x; @height-1x) { 21 | background-image: url("@{file-1x}"); 22 | 23 | @media 24 | only screen and (-webkit-min-device-pixel-ratio: 2), 25 | only screen and ( min--moz-device-pixel-ratio: 2), 26 | only screen and ( -o-min-device-pixel-ratio: 2/1), 27 | only screen and ( min-device-pixel-ratio: 2), 28 | only screen and ( min-resolution: 192dpi), 29 | only screen and ( min-resolution: 2dppx) { 30 | background-image: url("@{file-2x}"); 31 | background-size: @width-1x @height-1x; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/labels.less: -------------------------------------------------------------------------------- 1 | // Labels 2 | 3 | .label-variant(@color) { 4 | background-color: @color; 5 | 6 | &[href] { 7 | &:hover, 8 | &:focus { 9 | background-color: darken(@color, 10%); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/list-group.less: -------------------------------------------------------------------------------- 1 | // List Groups 2 | 3 | .list-group-item-variant(@state; @background; @color) { 4 | .list-group-item-@{state} { 5 | color: @color; 6 | background-color: @background; 7 | 8 | a&, 9 | button& { 10 | color: @color; 11 | 12 | .list-group-item-heading { 13 | color: inherit; 14 | } 15 | 16 | &:hover, 17 | &:focus { 18 | color: @color; 19 | background-color: darken(@background, 5%); 20 | } 21 | &.active, 22 | &.active:hover, 23 | &.active:focus { 24 | color: #fff; 25 | background-color: @color; 26 | border-color: @color; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/nav-divider.less: -------------------------------------------------------------------------------- 1 | // Horizontal dividers 2 | // 3 | // Dividers (basically an hr) within dropdowns and nav lists 4 | 5 | .nav-divider(@color: #e5e5e5) { 6 | height: 1px; 7 | margin: ((@line-height-computed / 2) - 1) 0; 8 | overflow: hidden; 9 | background-color: @color; 10 | } 11 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/nav-vertical-align.less: -------------------------------------------------------------------------------- 1 | // Navbar vertical align 2 | // 3 | // Vertically center elements in the navbar. 4 | // Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin. 5 | 6 | .navbar-vertical-align(@element-height) { 7 | margin-top: ((@navbar-height - @element-height) / 2); 8 | margin-bottom: ((@navbar-height - @element-height) / 2); 9 | } 10 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/opacity.less: -------------------------------------------------------------------------------- 1 | // Opacity 2 | 3 | .opacity(@opacity) { 4 | opacity: @opacity; 5 | // IE8 filter 6 | @opacity-ie: (@opacity * 100); 7 | filter: ~"alpha(opacity=@{opacity-ie})"; 8 | } 9 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/pagination.less: -------------------------------------------------------------------------------- 1 | // Pagination 2 | 3 | .pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { 4 | > li { 5 | > a, 6 | > span { 7 | padding: @padding-vertical @padding-horizontal; 8 | font-size: @font-size; 9 | line-height: @line-height; 10 | } 11 | &:first-child { 12 | > a, 13 | > span { 14 | .border-left-radius(@border-radius); 15 | } 16 | } 17 | &:last-child { 18 | > a, 19 | > span { 20 | .border-right-radius(@border-radius); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/panels.less: -------------------------------------------------------------------------------- 1 | // Panels 2 | 3 | .panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) { 4 | border-color: @border; 5 | 6 | & > .panel-heading { 7 | color: @heading-text-color; 8 | background-color: @heading-bg-color; 9 | border-color: @heading-border; 10 | 11 | + .panel-collapse > .panel-body { 12 | border-top-color: @border; 13 | } 14 | .badge { 15 | color: @heading-bg-color; 16 | background-color: @heading-text-color; 17 | } 18 | } 19 | & > .panel-footer { 20 | + .panel-collapse > .panel-body { 21 | border-bottom-color: @border; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/progress-bar.less: -------------------------------------------------------------------------------- 1 | // Progress bars 2 | 3 | .progress-bar-variant(@color) { 4 | background-color: @color; 5 | 6 | // Deprecated parent class requirement as of v3.2.0 7 | .progress-striped & { 8 | #gradient > .striped(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/reset-filter.less: -------------------------------------------------------------------------------- 1 | // Reset filters for IE 2 | // 3 | // When you need to remove a gradient background, do not forget to use this to reset 4 | // the IE filter for IE9 and below. 5 | 6 | .reset-filter() { 7 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); 8 | } 9 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/reset-text.less: -------------------------------------------------------------------------------- 1 | .reset-text() { 2 | font-family: @font-family-base; 3 | // We deliberately do NOT reset font-size. 4 | font-style: normal; 5 | font-weight: normal; 6 | letter-spacing: normal; 7 | line-break: auto; 8 | line-height: @line-height-base; 9 | text-align: left; // Fallback for where `start` is not supported 10 | text-align: start; 11 | text-decoration: none; 12 | text-shadow: none; 13 | text-transform: none; 14 | white-space: normal; 15 | word-break: normal; 16 | word-spacing: normal; 17 | word-wrap: normal; 18 | } 19 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/resize.less: -------------------------------------------------------------------------------- 1 | // Resize anything 2 | 3 | .resizable(@direction) { 4 | resize: @direction; // Options: horizontal, vertical, both 5 | overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` 6 | } 7 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/responsive-visibility.less: -------------------------------------------------------------------------------- 1 | // Responsive utilities 2 | 3 | // 4 | // More easily include all the states for responsive-utilities.less. 5 | .responsive-visibility() { 6 | display: block !important; 7 | table& { display: table !important; } 8 | tr& { display: table-row !important; } 9 | th&, 10 | td& { display: table-cell !important; } 11 | } 12 | 13 | .responsive-invisibility() { 14 | display: none !important; 15 | } 16 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/size.less: -------------------------------------------------------------------------------- 1 | // Sizing shortcuts 2 | 3 | .size(@width; @height) { 4 | width: @width; 5 | height: @height; 6 | } 7 | 8 | .square(@size) { 9 | .size(@size; @size); 10 | } 11 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/tab-focus.less: -------------------------------------------------------------------------------- 1 | // WebKit-style focus 2 | 3 | .tab-focus() { 4 | // Default 5 | outline: thin dotted; 6 | // WebKit 7 | outline: 5px auto -webkit-focus-ring-color; 8 | outline-offset: -2px; 9 | } 10 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/table-row.less: -------------------------------------------------------------------------------- 1 | // Tables 2 | 3 | .table-row-variant(@state; @background) { 4 | // Exact selectors below required to override `.table-striped` and prevent 5 | // inheritance to nested tables. 6 | .table > thead > tr, 7 | .table > tbody > tr, 8 | .table > tfoot > tr { 9 | > td.@{state}, 10 | > th.@{state}, 11 | &.@{state} > td, 12 | &.@{state} > th { 13 | background-color: @background; 14 | } 15 | } 16 | 17 | // Hover states for `.table-hover` 18 | // Note: this is not available for cells or rows within `thead` or `tfoot`. 19 | .table-hover > tbody > tr { 20 | > td.@{state}:hover, 21 | > th.@{state}:hover, 22 | &.@{state}:hover > td, 23 | &:hover > .@{state}, 24 | &.@{state}:hover > th { 25 | background-color: darken(@background, 5%); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/text-emphasis.less: -------------------------------------------------------------------------------- 1 | // Typography 2 | 3 | .text-emphasis-variant(@color) { 4 | color: @color; 5 | a&:hover, 6 | a&:focus { 7 | color: darken(@color, 10%); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/mixins/text-overflow.less: -------------------------------------------------------------------------------- 1 | // Text overflow 2 | // Requires inline-block or block for proper styling 3 | 4 | .text-overflow() { 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | white-space: nowrap; 8 | } 9 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/pager.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pager pagination 3 | // -------------------------------------------------- 4 | 5 | 6 | .pager { 7 | padding-left: 0; 8 | margin: @line-height-computed 0; 9 | list-style: none; 10 | text-align: center; 11 | &:extend(.clearfix all); 12 | li { 13 | display: inline; 14 | > a, 15 | > span { 16 | display: inline-block; 17 | padding: 5px 14px; 18 | background-color: @pager-bg; 19 | border: 1px solid @pager-border; 20 | border-radius: @pager-border-radius; 21 | } 22 | 23 | > a:hover, 24 | > a:focus { 25 | text-decoration: none; 26 | background-color: @pager-hover-bg; 27 | } 28 | } 29 | 30 | .next { 31 | > a, 32 | > span { 33 | float: right; 34 | } 35 | } 36 | 37 | .previous { 38 | > a, 39 | > span { 40 | float: left; 41 | } 42 | } 43 | 44 | .disabled { 45 | > a, 46 | > a:hover, 47 | > a:focus, 48 | > span { 49 | color: @pager-disabled-color; 50 | background-color: @pager-bg; 51 | cursor: @cursor-disabled; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/pagination.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pagination (multiple pages) 3 | // -------------------------------------------------- 4 | .pagination { 5 | display: inline-block; 6 | padding-left: 0; 7 | margin: @line-height-computed 0; 8 | border-radius: @border-radius-base; 9 | 10 | > li { 11 | display: inline; // Remove list-style and block-level defaults 12 | > a, 13 | > span { 14 | position: relative; 15 | float: left; // Collapse white-space 16 | padding: @padding-base-vertical @padding-base-horizontal; 17 | line-height: @line-height-base; 18 | text-decoration: none; 19 | color: @pagination-color; 20 | background-color: @pagination-bg; 21 | border: 1px solid @pagination-border; 22 | margin-left: -1px; 23 | } 24 | &:first-child { 25 | > a, 26 | > span { 27 | margin-left: 0; 28 | .border-left-radius(@border-radius-base); 29 | } 30 | } 31 | &:last-child { 32 | > a, 33 | > span { 34 | .border-right-radius(@border-radius-base); 35 | } 36 | } 37 | } 38 | 39 | > li > a, 40 | > li > span { 41 | &:hover, 42 | &:focus { 43 | z-index: 2; 44 | color: @pagination-hover-color; 45 | background-color: @pagination-hover-bg; 46 | border-color: @pagination-hover-border; 47 | } 48 | } 49 | 50 | > .active > a, 51 | > .active > span { 52 | &, 53 | &:hover, 54 | &:focus { 55 | z-index: 3; 56 | color: @pagination-active-color; 57 | background-color: @pagination-active-bg; 58 | border-color: @pagination-active-border; 59 | cursor: default; 60 | } 61 | } 62 | 63 | > .disabled { 64 | > span, 65 | > span:hover, 66 | > span:focus, 67 | > a, 68 | > a:hover, 69 | > a:focus { 70 | color: @pagination-disabled-color; 71 | background-color: @pagination-disabled-bg; 72 | border-color: @pagination-disabled-border; 73 | cursor: @cursor-disabled; 74 | } 75 | } 76 | } 77 | 78 | // Sizing 79 | // -------------------------------------------------- 80 | 81 | // Large 82 | .pagination-lg { 83 | .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large); 84 | } 85 | 86 | // Small 87 | .pagination-sm { 88 | .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small); 89 | } 90 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/print.less: -------------------------------------------------------------------------------- 1 | /*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ 2 | 3 | // ========================================================================== 4 | // Print styles. 5 | // Inlined to avoid the additional HTTP request: h5bp.com/r 6 | // ========================================================================== 7 | 8 | @media print { 9 | *, 10 | *:before, 11 | *:after { 12 | background: transparent !important; 13 | color: #000 !important; // Black prints faster: h5bp.com/s 14 | box-shadow: none !important; 15 | text-shadow: none !important; 16 | } 17 | 18 | a, 19 | a:visited { 20 | text-decoration: underline; 21 | } 22 | 23 | a[href]:after { 24 | content: " (" attr(href) ")"; 25 | } 26 | 27 | abbr[title]:after { 28 | content: " (" attr(title) ")"; 29 | } 30 | 31 | // Don't show links that are fragment identifiers, 32 | // or use the `javascript:` pseudo protocol 33 | a[href^="#"]:after, 34 | a[href^="javascript:"]:after { 35 | content: ""; 36 | } 37 | 38 | pre, 39 | blockquote { 40 | border: 1px solid #999; 41 | page-break-inside: avoid; 42 | } 43 | 44 | thead { 45 | display: table-header-group; // h5bp.com/t 46 | } 47 | 48 | tr, 49 | img { 50 | page-break-inside: avoid; 51 | } 52 | 53 | img { 54 | max-width: 100% !important; 55 | } 56 | 57 | p, 58 | h2, 59 | h3 { 60 | orphans: 3; 61 | widows: 3; 62 | } 63 | 64 | h2, 65 | h3 { 66 | page-break-after: avoid; 67 | } 68 | 69 | // Bootstrap specific changes start 70 | 71 | // Bootstrap components 72 | .navbar { 73 | display: none; 74 | } 75 | .btn, 76 | .dropup > .btn { 77 | > .caret { 78 | border-top-color: #000 !important; 79 | } 80 | } 81 | .label { 82 | border: 1px solid #000; 83 | } 84 | 85 | .table { 86 | border-collapse: collapse !important; 87 | 88 | td, 89 | th { 90 | background-color: #fff !important; 91 | } 92 | } 93 | .table-bordered { 94 | th, 95 | td { 96 | border: 1px solid #ddd !important; 97 | } 98 | } 99 | 100 | // Bootstrap specific changes end 101 | } 102 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/progress-bars.less: -------------------------------------------------------------------------------- 1 | // 2 | // Progress bars 3 | // -------------------------------------------------- 4 | 5 | 6 | // Bar animations 7 | // ------------------------- 8 | 9 | // WebKit 10 | @-webkit-keyframes progress-bar-stripes { 11 | from { background-position: 40px 0; } 12 | to { background-position: 0 0; } 13 | } 14 | 15 | // Spec and IE10+ 16 | @keyframes progress-bar-stripes { 17 | from { background-position: 40px 0; } 18 | to { background-position: 0 0; } 19 | } 20 | 21 | 22 | // Bar itself 23 | // ------------------------- 24 | 25 | // Outer container 26 | .progress { 27 | overflow: hidden; 28 | height: @line-height-computed; 29 | margin-bottom: @line-height-computed; 30 | background-color: @progress-bg; 31 | border-radius: @progress-border-radius; 32 | .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); 33 | } 34 | 35 | // Bar of progress 36 | .progress-bar { 37 | float: left; 38 | width: 0%; 39 | height: 100%; 40 | font-size: @font-size-small; 41 | line-height: @line-height-computed; 42 | color: @progress-bar-color; 43 | text-align: center; 44 | background-color: @progress-bar-bg; 45 | .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); 46 | .transition(width .6s ease); 47 | } 48 | 49 | // Striped bars 50 | // 51 | // `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the 52 | // `.progress-bar-striped` class, which you just add to an existing 53 | // `.progress-bar`. 54 | .progress-striped .progress-bar, 55 | .progress-bar-striped { 56 | #gradient > .striped(); 57 | background-size: 40px 40px; 58 | } 59 | 60 | // Call animation for the active one 61 | // 62 | // `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the 63 | // `.progress-bar.active` approach. 64 | .progress.active .progress-bar, 65 | .progress-bar.active { 66 | .animation(progress-bar-stripes 2s linear infinite); 67 | } 68 | 69 | 70 | // Variations 71 | // ------------------------- 72 | 73 | .progress-bar-success { 74 | .progress-bar-variant(@progress-bar-success-bg); 75 | } 76 | 77 | .progress-bar-info { 78 | .progress-bar-variant(@progress-bar-info-bg); 79 | } 80 | 81 | .progress-bar-warning { 82 | .progress-bar-variant(@progress-bar-warning-bg); 83 | } 84 | 85 | .progress-bar-danger { 86 | .progress-bar-variant(@progress-bar-danger-bg); 87 | } 88 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/responsive-embed.less: -------------------------------------------------------------------------------- 1 | // Embeds responsive 2 | // 3 | // Credit: Nicolas Gallagher and SUIT CSS. 4 | 5 | .embed-responsive { 6 | position: relative; 7 | display: block; 8 | height: 0; 9 | padding: 0; 10 | overflow: hidden; 11 | 12 | .embed-responsive-item, 13 | iframe, 14 | embed, 15 | object, 16 | video { 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | bottom: 0; 21 | height: 100%; 22 | width: 100%; 23 | border: 0; 24 | } 25 | } 26 | 27 | // Modifier class for 16:9 aspect ratio 28 | .embed-responsive-16by9 { 29 | padding-bottom: 56.25%; 30 | } 31 | 32 | // Modifier class for 4:3 aspect ratio 33 | .embed-responsive-4by3 { 34 | padding-bottom: 75%; 35 | } 36 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/thumbnails.less: -------------------------------------------------------------------------------- 1 | // 2 | // Thumbnails 3 | // -------------------------------------------------- 4 | 5 | 6 | // Mixin and adjust the regular image class 7 | .thumbnail { 8 | display: block; 9 | padding: @thumbnail-padding; 10 | margin-bottom: @line-height-computed; 11 | line-height: @line-height-base; 12 | background-color: @thumbnail-bg; 13 | border: 1px solid @thumbnail-border; 14 | border-radius: @thumbnail-border-radius; 15 | .transition(border .2s ease-in-out); 16 | 17 | > img, 18 | a > img { 19 | &:extend(.img-responsive); 20 | margin-left: auto; 21 | margin-right: auto; 22 | } 23 | 24 | // Add a hover state for linked versions only 25 | a&:hover, 26 | a&:focus, 27 | a&.active { 28 | border-color: @link-color; 29 | } 30 | 31 | // Image captions 32 | .caption { 33 | padding: @thumbnail-caption-padding; 34 | color: @thumbnail-caption-color; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // Floats 7 | // ------------------------- 8 | 9 | .clearfix { 10 | .clearfix(); 11 | } 12 | .center-block { 13 | .center-block(); 14 | } 15 | .pull-right { 16 | float: right !important; 17 | } 18 | .pull-left { 19 | float: left !important; 20 | } 21 | 22 | 23 | // Toggling content 24 | // ------------------------- 25 | 26 | // Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1 27 | .hide { 28 | display: none !important; 29 | } 30 | .show { 31 | display: block !important; 32 | } 33 | .invisible { 34 | visibility: hidden; 35 | } 36 | .text-hide { 37 | .text-hide(); 38 | } 39 | 40 | 41 | // Hide from screenreaders and browsers 42 | // 43 | // Credit: HTML5 Boilerplate 44 | 45 | .hidden { 46 | display: none !important; 47 | } 48 | 49 | 50 | // For Affix plugin 51 | // ------------------------- 52 | 53 | .affix { 54 | position: fixed; 55 | } 56 | -------------------------------------------------------------------------------- /neonion/static/bootstrap/less/wells.less: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .well { 8 | min-height: 20px; 9 | padding: 19px; 10 | margin-bottom: 20px; 11 | background-color: @well-bg; 12 | border: 1px solid @well-border; 13 | border-radius: @border-radius-base; 14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); 15 | blockquote { 16 | border-color: #ddd; 17 | border-color: rgba(0,0,0,.15); 18 | } 19 | } 20 | 21 | // Sizes 22 | .well-lg { 23 | padding: 24px; 24 | border-radius: @border-radius-large; 25 | } 26 | .well-sm { 27 | padding: 9px; 28 | border-radius: @border-radius-small; 29 | } 30 | -------------------------------------------------------------------------------- /neonion/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/favicon.ico -------------------------------------------------------------------------------- /neonion/static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Bold-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Bold-latin-ext.woff2 -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Bold-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Bold-latin.woff2 -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Bold.woff -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Light-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Light-latin-ext.woff2 -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Light-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Light-latin.woff2 -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Light.woff -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Regular-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Regular-latin-ext.woff2 -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Regular-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Regular-latin.woff2 -------------------------------------------------------------------------------- /neonion/static/fonts/Lato/Lato-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/Lato/Lato-Regular.woff -------------------------------------------------------------------------------- /neonion/static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /neonion/static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /neonion/static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /neonion/static/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /neonion/static/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var styleguide = require('sc5-styleguide'); 3 | var less = require('gulp-less'); 4 | var outputPath = 'styleguide'; 5 | var concat = require("gulp-concat"); 6 | 7 | gulp.task('styleguide:generate', function() { 8 | return gulp.src('less/**/*.less') 9 | .pipe(styleguide.generate({ 10 | title: 'Styleguide for neonion', 11 | server: true, 12 | rootPath: outputPath, 13 | overviewPath: 'less/styleguide.md', 14 | commonClass: 'myfont', 15 | extraHead: [ 16 | '', 17 | '' 18 | ], 19 | disableEncapsulation: true, 20 | customColors: 'utils/styleguide.scss' 21 | })) 22 | .pipe(gulp.dest(outputPath)); 23 | }); 24 | 25 | gulp.task('styleguide:applystyles', function() { 26 | return gulp.src([ 27 | 'less/my-bootstrap-theme.less', 28 | 'utils/additional.less' 29 | ]) 30 | .pipe(concat('all.less')) 31 | .pipe(less({ 32 | errLogToConsole: true 33 | })) 34 | .pipe(styleguide.applyStyles()) 35 | .pipe(gulp.dest(outputPath)); 36 | }); 37 | 38 | gulp.task('styleguide:static', function() { 39 | gulp.src('fonts/**') 40 | .pipe(gulp.dest(outputPath + '/fonts')); 41 | gulp.src('js/jquery.min.js') 42 | .pipe(gulp.dest(outputPath + '/js')); 43 | gulp.src('js/bootstrap.min.js') 44 | .pipe(gulp.dest(outputPath + '/js')); 45 | }); 46 | 47 | gulp.task('watch', ['styleguide'], function() { 48 | // Start watching changes and update styleguide whenever changes are detected 49 | // Styleguide automatically detects existing server instance 50 | 51 | gulp.watch(['less/**/*.less'], ['styleguide']); 52 | }); 53 | 54 | gulp.task('styleguide', [ 55 | 'styleguide:static', 56 | 'styleguide:generate', 57 | 'styleguide:applystyles' 58 | ]); -------------------------------------------------------------------------------- /neonion/static/img/annotator-glyph-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/img/annotator-glyph-sprite.png -------------------------------------------------------------------------------- /neonion/static/img/annotator-icon-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/img/annotator-icon-sprite.png -------------------------------------------------------------------------------- /neonion/static/img/annotator/relation_checkmark_black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /neonion/static/img/annotator/relation_checkmark_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /neonion/static/img/annotator/relation_create.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /neonion/static/img/annotator/relation_edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /neonion/static/img/annotator/relation_remove_black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /neonion/static/img/annotator/relation_remove_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /neonion/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/img/logo.png -------------------------------------------------------------------------------- /neonion/static/img/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/static/img/unknown.png -------------------------------------------------------------------------------- /neonion/static/js/angular/app.js: -------------------------------------------------------------------------------- 1 | var neonionApp = angular.module('neonionApp', [ 2 | 'ngResource', 'ngCookies', 'angular.filter', 'ngFileUpload', 'components' 3 | ]) 4 | .config(['$httpProvider', '$locationProvider', 5 | function ($httpProvider, $locationProvider) { 6 | "use strict"; 7 | //$locationProvider.html5Mode(false); 8 | // CSRF settings 9 | $httpProvider.defaults.xsrfCookieName = 'csrftoken'; 10 | $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; 11 | } 12 | ]) 13 | .constant("cookieKeys", { 14 | annotationMode: "neonion_annotationMode" 15 | } 16 | ) 17 | -------------------------------------------------------------------------------- /neonion/static/js/angular/components.js: -------------------------------------------------------------------------------- 1 | angular.module('components', []) 2 | // directive for annotator 3 | .directive('annotator', function () { 4 | return { 5 | restrict: 'E', 6 | scope: { 7 | groupId: "@groupId", 8 | documentId: "@documentId" 9 | }, 10 | controller: 'AnnotatorCtrl', 11 | templateUrl: '/static/partials/annotator/annotator.html' 12 | }; 13 | }) 14 | 15 | // directive for annotator context 16 | .directive('annotatorContext', function () { 17 | return { 18 | restrict: 'E', 19 | scope: { 20 | groupId: "@groupId", 21 | documentId: "@documentId" 22 | }, 23 | controller: 'ContextInfoCtrl', 24 | templateUrl: '/static/partials/annotator/annotator-context.html' 25 | }; 26 | }) 27 | 28 | // directive to render a PDF document 29 | .directive('pdfRender', function () { 30 | return { 31 | restrict: 'E', 32 | scope: { 33 | path: "@path" 34 | }, 35 | controller: 'AnnotatorPDFCtrl', 36 | template: '
' 37 | }; 38 | }) 39 | 40 | // directive to render a plain text document 41 | .directive('plainRender', function () { 42 | return { 43 | restrict: 'E', 44 | controller: function ($scope) { 45 | $scope.completed = function () { 46 | $scope.$emit("allPagesRendered"); 47 | }; 48 | $scope.$emit("renderTemplateLoaded"); 49 | }, 50 | scope: { 51 | path: "@path" 52 | }, 53 | template: '
' + 54 | '
' + 55 | '
' 56 | }; 57 | }) 58 | 59 | // directive for filter field 60 | .directive('filter', function () { 61 | return { 62 | restrict: 'E', 63 | scope: false, 64 | template: '' 66 | }; 67 | }) 68 | 69 | // directive for logged in user 70 | .directive('loggedUser', function () { 71 | return { 72 | restrict: 'E', 73 | scope: false, 74 | template: ' {{ user.email }}' 75 | }; 76 | }); -------------------------------------------------------------------------------- /neonion/static/js/angular/controllers/accounts/user-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * User list controller 3 | */ 4 | neonionApp.controller('UserListCtrl', ['$scope', 'UserService', 5 | function ($scope, UserService) { 6 | "use strict"; 7 | 8 | $scope.users = UserService.query(); 9 | 10 | $scope.update = function (user, field, value) { 11 | if (user.hasOwnProperty(field) && user[field] != value) { 12 | user[field] = value; 13 | user.$update(); 14 | } 15 | }; 16 | 17 | $scope.delete = function (user) { 18 | user.$delete().then(function () { 19 | var idx = $scope.users.indexOf(user); 20 | $scope.users.splice(idx, 1); 21 | }); 22 | }; 23 | 24 | }]); -------------------------------------------------------------------------------- /neonion/static/js/angular/controllers/annotations/occurrence-list.js: -------------------------------------------------------------------------------- 1 | neonionApp.controller('AnnotationOccurrenceListCtrl', ['$scope', '$location', 2 | 'DocumentService', 'AnnotationStoreService', 3 | function ($scope, $location, DocumentService, AnnotationStoreService) { 4 | "use strict"; 5 | 6 | $scope.queryDocumentTitles = function () { 7 | return DocumentService.queryTitles(function (titles) { 8 | $scope.documentTitles = titles; 9 | }).$promise; 10 | } 11 | 12 | $scope.queryAnnotations = function() { 13 | // TODO consider query params to dispatch annotation retrieval method 14 | // case query parm contains 'rdf.uri' 15 | return $scope.getAnnotationsOfConcept(); 16 | } 17 | 18 | $scope.getAnnotationsOfConcept = function () { 19 | return AnnotationStoreService.search($location.search(), function (annotations) { 20 | $scope.annotations = annotations.filter(function (item) { 21 | return $scope.documentTitles.hasOwnProperty(item.uri); 22 | }); 23 | }).$promise; 24 | }; 25 | 26 | // execute promise chain 27 | $scope.queryDocumentTitles() 28 | .then($scope.queryAnnotations); 29 | 30 | } 31 | ]); -------------------------------------------------------------------------------- /neonion/static/js/angular/controllers/annotator/annotator-context.js: -------------------------------------------------------------------------------- 1 | /*jshint jquery:true */ 2 | 3 | /** 4 | * ContextInfo controller 5 | */ 6 | neonionApp.controller('ContextInfoCtrl', ['$scope', '$location', 'CommonService', 'AnnotatorService', 'DocumentService', 'GroupService', 7 | function ($scope, $location, CommonService, AnnotatorService, DocumentService, GroupService) { 8 | "use strict"; 9 | 10 | $scope.getCurrentUser = function () { 11 | return CommonService.getCurrentUser(function (user) { 12 | $scope.user = user; 13 | }).$promise; 14 | }; 15 | 16 | $scope.getDocument = function () { 17 | if ($scope.hasOwnProperty("documentId")) { 18 | return DocumentService.get({id: $scope.documentId}, function (document) { 19 | $scope.document = document; 20 | }).$promise; 21 | } 22 | else { 23 | return Promise.resolve(true); 24 | } 25 | }; 26 | 27 | $scope.getGroup = function () { 28 | if ($scope.hasOwnProperty("groupId")) { 29 | var groupId = parseInt($scope.groupId); 30 | if (!isNaN(groupId)) { 31 | // get the group object 32 | return GroupService.get({id: groupId}, function (group) { 33 | $scope.isPrivate = false; 34 | $scope.group = group; 35 | }).$promise; 36 | } 37 | else { 38 | $scope.isPrivate = true; 39 | // no http communication 40 | return Promise.resolve(true); 41 | } 42 | } 43 | else { 44 | return Promise.resolve(true); 45 | } 46 | }; 47 | 48 | // execute promise chain 49 | $scope.getCurrentUser() 50 | .then($scope.getDocument) 51 | .then($scope.getGroup) 52 | .then(function () { 53 | $scope.annotatorService = AnnotatorService; 54 | }); 55 | 56 | }]); -------------------------------------------------------------------------------- /neonion/static/js/angular/controllers/common/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Main controller for the whole application 3 | */ 4 | neonionApp.controller('MainCtrl', ['$scope', 'CommonService', 5 | function ($scope, CommonService) { 6 | "use strict"; 7 | $scope.common = CommonService; 8 | 9 | $scope.getCurrentUser = function () { 10 | return CommonService.getCurrentUser(function (user) { 11 | $scope.user = user; 12 | }).$promise; 13 | }; 14 | 15 | $scope.getCurrentUser() 16 | }]); -------------------------------------------------------------------------------- /neonion/static/js/angular/controllers/vocabulary/concept-list.js: -------------------------------------------------------------------------------- 1 | neonionApp.controller('ConceptListCtrl', ['$scope', '$sce', 'CommonService', 'ConceptService', 'PropertyService', 2 | function ($scope, $sce, CommonService, ConceptService, PropertyService) { 3 | "use strict"; 4 | 5 | $scope.listModeEnabled = true; 6 | $scope.style = { 7 | compact: true, 8 | allowCreate : true, 9 | detailTemplateUrl : "/static/partials/vocabulary/concept-detail.html" 10 | }; 11 | $scope.locales = { 12 | // TODO localize 13 | create: "Create Concept" 14 | }; 15 | 16 | $scope.queryConcepts = function () { 17 | return ConceptService.query(function (data) { 18 | $scope.resources = data; 19 | }).$promise; 20 | }; 21 | 22 | $scope.queryProperties = function () { 23 | return PropertyService.query(function (data) { 24 | $scope.properties = data; 25 | }).$promise; 26 | }; 27 | 28 | $scope.createItem = function() { 29 | $scope.listModeEnabled = false; 30 | $scope.$broadcast("createEvent") 31 | }; 32 | 33 | $scope.editItem = function(item) { 34 | $scope.listModeEnabled = false; 35 | $scope.$broadcast("editEvent", item) 36 | }; 37 | 38 | $scope.getItemHeader = function (resource) { 39 | return $sce.trustAsHtml(resource.label); 40 | }; 41 | 42 | $scope.getItemDescription = function (resource) { 43 | return $sce.trustAsHtml(resource.comment); 44 | }; 45 | 46 | $scope.filterResources = function (resource) { 47 | if (CommonService.filter.query.length > 0) { 48 | return resource.label.toLowerCase().indexOf(CommonService.filter.query.toLowerCase()) != -1; 49 | } 50 | return true; 51 | }; 52 | 53 | var unbindReturnEvent = $scope.$on('returnEvent', function () { 54 | $scope.queryConcepts(); 55 | $scope.listModeEnabled = true; 56 | }); 57 | $scope.$on('$destroy', unbindReturnEvent); 58 | 59 | // execute promise chain 60 | $scope.queryConcepts(); 61 | 62 | }] 63 | ); -------------------------------------------------------------------------------- /neonion/static/js/angular/controllers/vocabulary/property-list.js: -------------------------------------------------------------------------------- 1 | neonionApp.controller('PropertyListCtrl', ['$scope', '$sce', 'CommonService', 'PropertyService', 2 | function ($scope, $sce, CommonService, PropertyService) { 3 | "use strict"; 4 | 5 | $scope.listModeEnabled = true; 6 | $scope.style = { 7 | compact: true, 8 | allowCreate : true, 9 | detailTemplateUrl : "/static/partials/vocabulary/property-detail.html" 10 | }; 11 | $scope.locales = { 12 | // TODO localize 13 | create: "Create Property" 14 | }; 15 | 16 | $scope.queryProperties = function () { 17 | return PropertyService.query(function (data) { 18 | $scope.resources = data; 19 | }).$promise; 20 | }; 21 | 22 | $scope.createItem = function() { 23 | $scope.listModeEnabled = false; 24 | $scope.$broadcast("createEvent") 25 | }; 26 | 27 | $scope.editItem = function(item) { 28 | $scope.listModeEnabled = false; 29 | $scope.$broadcast("editEvent", item) 30 | }; 31 | 32 | $scope.getItemHeader = function (resource) { 33 | return $sce.trustAsHtml(resource.label); 34 | }; 35 | 36 | $scope.getItemDescription = function (resource) { 37 | return $sce.trustAsHtml(resource.comment); 38 | }; 39 | 40 | $scope.filterResources = function (resource) { 41 | if (CommonService.filter.query.length > 0) { 42 | return resource.label.toLowerCase().indexOf(CommonService.filter.query.toLowerCase()) != -1; 43 | } 44 | return true; 45 | }; 46 | 47 | var unbindReturnEvent = $scope.$on('returnEvent', function () { 48 | $scope.queryProperties(); 49 | $scope.listModeEnabled = true; 50 | }); 51 | $scope.$on('$destroy', unbindReturnEvent); 52 | 53 | // execute promise chain 54 | $scope.queryProperties(); 55 | 56 | }] 57 | ); -------------------------------------------------------------------------------- /neonion/static/js/angular/controllers/workbench/bulk-upload.js: -------------------------------------------------------------------------------- 1 | neonionApp.controller('BulkUploadCtrl', ['$scope', 'Upload', 2 | function ($scope, Upload) { 3 | 4 | $scope.form = { 5 | index: "", 6 | type: "", 7 | upload : { 8 | uploading : false, 9 | progress : 0 10 | } 11 | }; 12 | $scope.upload = null; 13 | 14 | $scope.validate = function() { 15 | return !$scope.form.upload.uploading && 16 | $scope.form.index.length > 0 && 17 | $scope.form.type.length > 0; 18 | }; 19 | 20 | $scope.uploadFile = function (file) { 21 | if ($scope.validate() && file) { 22 | $scope.form.upload.uploading = true; 23 | $scope.form.upload.progress = 0; 24 | 25 | $scope.upload = Upload.upload({ 26 | url: 'api/es/import/' + $scope.form.index + "/" + $scope.form.type, 27 | file: file 28 | }).progress(function (evt) { 29 | var progressPercentage = parseInt(100.0 * evt.loaded / evt.total); 30 | $scope.form.upload.progress = progressPercentage; 31 | console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name); 32 | }).success(function (data, status, headers, config) { 33 | $scope.form.upload.uploading = false; 34 | console.log('file ' + config.file.name + 'uploaded. Response: ' + data); 35 | }).error(function (data, status, headers, config) { 36 | $scope.form.upload.uploading = false; 37 | console.log('error status: ' + status); 38 | }) 39 | } 40 | }; 41 | 42 | $scope.cancelUpload = function() { 43 | if ($scope.form.upload.uploading) { 44 | $scope.upload.abort(); 45 | $scope.form.upload.uploading = false; 46 | $scope.form.upload.progress = 0; 47 | } 48 | } 49 | }] 50 | ); 51 | -------------------------------------------------------------------------------- /neonion/static/js/angular/controllers/workbench/orphaned-annotation-list.js: -------------------------------------------------------------------------------- 1 | neonionApp.controller('OrphanedAnnotationListCtrl', ['$scope', '$sce', 'DocumentService', 'AnnotationStoreService', 2 | function ($scope, $sce, DocumentService, AnnotationStoreService) { 3 | "use strict"; 4 | 5 | $scope.stepSize = 25; 6 | $scope.resources = []; 7 | 8 | $scope.queryDocuments = function () { 9 | return DocumentService.queryTitles(function (data) { 10 | $scope.documentTitles = data; 11 | }).$promise; 12 | }; 13 | 14 | $scope.getQueryParams = function (pageNum) { 15 | return { 16 | offset: pageNum * $scope.stepSize, 17 | limit: $scope.stepSize 18 | }; 19 | } 20 | 21 | $scope.queryOrphanedAnnotations = function (documentTitles, pageNum) { 22 | pageNum = pageNum | 0; 23 | return AnnotationStoreService.search($scope.getQueryParams(pageNum), function (data) { 24 | if (data.length > 0) { 25 | var orphanedAnnotations = data.filter(function (annotation) { 26 | return !documentTitles.hasOwnProperty(annotation.uri); 27 | }); 28 | $scope.resources = $scope.resources.concat(orphanedAnnotations); 29 | 30 | // get next annotations 31 | $scope.queryOrphanedAnnotations(documentTitles, pageNum + 1); 32 | } 33 | }).$promise; 34 | }; 35 | 36 | $scope.deleteAnnotation = function (annotation) { 37 | return annotation.$delete(function () { 38 | var annotationIdx = $scope.resources.indexOf(annotation); 39 | $scope.resources.splice(annotationIdx, 1); 40 | }).$promise; 41 | } 42 | 43 | $scope.deleteAnnotations = function (annotations) { 44 | annotations.forEach(function (annotation) { 45 | $scope.deleteAnnotation(annotation); 46 | }); 47 | } 48 | 49 | // execute promise chain 50 | $scope.queryDocuments() 51 | .then($scope.queryOrphanedAnnotations); 52 | 53 | }] 54 | ); -------------------------------------------------------------------------------- /neonion/static/js/angular/filters.js: -------------------------------------------------------------------------------- 1 | neonionApp 2 | .filter('escape', function () { 3 | return window.encodeURIComponent; 4 | }) 5 | .filter('truncate', function () { 6 | return function (text, position) { 7 | if (position == 'left') 8 | text = '[...]\u00A0' + text; 9 | 10 | if (position == 'right') 11 | text = text + '\u00A0[...]'; 12 | 13 | return text; 14 | }; 15 | }) 16 | .filter('filterByConceptAnnotation', function () { 17 | return function (annotations) { 18 | if (!angular.isUndefined(annotations)) { 19 | return annotations.filter(function (value) { 20 | return (value['oa']['motivatedBy'] == "oa:classifying" || 21 | value['oa']['motivatedBy'] == "oa:identifying"); 22 | }); 23 | } 24 | else { 25 | return []; 26 | } 27 | }; 28 | }) 29 | .filter('filterByLinkedAnnotation', function () { 30 | return function (annotations) { 31 | if (!angular.isUndefined(annotations)) { 32 | return annotations.filter(function (value) { 33 | return (value['oa']['motivatedBy'] == "oa:linking"); 34 | }); 35 | } 36 | else { 37 | return []; 38 | } 39 | }; 40 | }) 41 | .filter('filterByCommentAnnotation', function () { 42 | return function (annotations) { 43 | if (!angular.isUndefined(annotations)) { 44 | return annotations.filter(function (value) { 45 | return (value['oa']['motivatedBy'] == "oa:commenting"); 46 | }); 47 | } 48 | else { 49 | return []; 50 | } 51 | }; 52 | }) 53 | .filter('filterByHighlightAnnotation', function () { 54 | return function (annotations) { 55 | if (!angular.isUndefined(annotations)) { 56 | return annotations.filter(function (value) { 57 | return (value['oa']['motivatedBy'] == "oa:highlighting"); 58 | }); 59 | } 60 | else { 61 | return []; 62 | } 63 | }; 64 | }); -------------------------------------------------------------------------------- /neonion/static/js/angular/lib/angular-cookies.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.4.3 3 | (c) 2010-2015 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(p,g,l){'use strict';function m(b,a,f){var c=f.baseHref(),k=b[0];return function(b,d,e){var f,h;e=e||{};h=e.expires;f=g.isDefined(e.path)?e.path:c;d===l&&(h="Thu, 01 Jan 1970 00:00:00 GMT",d="");g.isString(h)&&(h=new Date(h));d=encodeURIComponent(b)+"="+encodeURIComponent(d);d=d+(f?";path="+f:"")+(e.domain?";domain="+e.domain:"");d+=h?";expires="+h.toUTCString():"";d+=e.secure?";secure":"";e=d.length+1;4096 4096 bytes)!");k.cookie=d}}g.module("ngCookies",["ng"]).provider("$cookies",[function(){var b=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(a,f){return{get:function(c){return a()[c]},getObject:function(c){return(c=this.get(c))?g.fromJson(c):c},getAll:function(){return a()},put:function(c,a,n){f(c,a,n?g.extend({},b,n):b)},putObject:function(c,b,a){this.put(c,g.toJson(b),a)},remove:function(a,k){f(a,l,k?g.extend({},b,k):b)}}}]}]);g.module("ngCookies").factory("$cookieStore", 8 | ["$cookies",function(b){return{get:function(a){return b.getObject(a)},put:function(a,f){b.putObject(a,f)},remove:function(a){b.remove(a)}}}]);m.$inject=["$document","$log","$browser"];g.module("ngCookies").provider("$$cookieWriter",function(){this.$get=m})})(window,window.angular); 9 | //# sourceMappingURL=angular-cookies.min.js.map 10 | -------------------------------------------------------------------------------- /neonion/static/js/angular/root.js: -------------------------------------------------------------------------------- 1 | neonionApp 2 | .run(function ($rootScope) { 3 | 4 | /** 5 | * Transform the given data to a CSV export 6 | */ 7 | $rootScope.exportCSV = function (data, properties, separator) { 8 | separator = separator || ';' 9 | var csvContent = 'data:text/csv;charset=utf-8,'; 10 | // create array to store lines 11 | var lines = []; 12 | // add header information 13 | lines.push(properties.join(separator)); 14 | // create array to store each field value 15 | var fields = []; 16 | fields.length = properties.length; 17 | 18 | // iterate over data items 19 | data.forEach(function (item) { 20 | // iterate over specified properties 21 | properties.forEach(function (property, index) { 22 | var subValue = item; 23 | // split property into keys 24 | var keys = property.split('.'); 25 | // iterate over keys in current property 26 | for (var i = 0; i < keys.length; i++) { 27 | if (subValue.hasOwnProperty(keys[i])) { 28 | subValue = subValue[keys[i]]; 29 | } 30 | else { 31 | subValue = ''; 32 | // exit if current key not exists 33 | break; 34 | } 35 | } 36 | // write value to field set 37 | fields[index] = JSON.stringify(subValue); 38 | }); 39 | lines.push(fields.join(separator)); 40 | }); 41 | // closure 42 | return csvContent + lines.join('%0A'); 43 | }; 44 | 45 | }); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/annotation-store.js: -------------------------------------------------------------------------------- 1 | neonionApp.factory('AnnotationStoreService', ['$resource', 2 | function ($resource) { 3 | return $resource('/store/annotations/:id', 4 | {id: '@id', limit: 999999}, 5 | { 6 | 'search': { 7 | method: 'GET', 8 | params: {limit: 999999}, 9 | isArray: true, 10 | cache: true, 11 | url: '/store/search', 12 | transformResponse: function (data, headersGetter) { 13 | return angular.fromJson(data)['rows']; 14 | } 15 | } 16 | } 17 | ); 18 | }] 19 | ); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Common Service to share data across controllers 3 | */ 4 | neonionApp.factory('CommonService', ['UserService', 5 | function (UserService) { 6 | "use strict"; 7 | 8 | var factory = { 9 | filter: { 10 | query: "" 11 | }, 12 | search: { 13 | query: "", 14 | enabled: false 15 | } 16 | }; 17 | 18 | factory.getCurrentUser = function (onFulfilled) { 19 | return UserService.current(onFulfilled); 20 | }; 21 | 22 | return factory; 23 | }] 24 | ); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/concept.js: -------------------------------------------------------------------------------- 1 | neonionApp.factory('ConceptService', ['$resource', 2 | function ($resource) { 3 | return $resource('/api/concepts/:id', 4 | {id: '@id'}, 5 | { 6 | 'save': {method: 'POST', url: '/api/concepts/'}, 7 | 'update': {method: 'PUT'}, 8 | } 9 | ); 10 | }] 11 | ); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/conceptset.js: -------------------------------------------------------------------------------- 1 | neonionApp.factory('ConceptSetService', ['$resource', 2 | function ($resource) { 3 | return $resource('/api/conceptsets/:id', 4 | {id: '@id'}, 5 | { 6 | 'save': {method: 'POST', url: '/api/conceptsets/'}, 7 | 'update': {method: 'PUT'}, 8 | 'getDeep': {method: 'GET', isArray: false, params: {deep: true}} 9 | } 10 | ); 11 | }] 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /neonion/static/js/angular/services/document.js: -------------------------------------------------------------------------------- 1 | neonionApp.factory('DocumentService', ['$resource', 2 | function ($resource) { 3 | return $resource('/api/documents/:id', 4 | {id: '@id'}, 5 | { 6 | 'queryTitles': { 7 | method: 'GET', 8 | params: {}, 9 | cache: true, 10 | transformResponse: function (data, header) { 11 | var jsonData = angular.fromJson(data); 12 | var names = {}; 13 | angular.forEach(jsonData, function (item) { 14 | names[item.id] = item.title; 15 | }); 16 | return names; 17 | } 18 | }, 19 | 'save': {method: 'POST', url:'/api/documents/'}, 20 | 'update': {method: 'PUT'} 21 | }); 22 | }] 23 | ); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/group.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @deprecated Service for groups 3 | */ 4 | neonionApp.factory('GroupService', ['$resource', 5 | function ($resource) { 6 | return $resource('/api/groups/:id', 7 | {id: '@id'}, 8 | { 9 | 'update': {method: 'PUT'}, 10 | 'queryGroupNames': { 11 | method: 'GET', 12 | params: {}, 13 | cache: true, 14 | transformResponse: function (data, header) { 15 | var jsonData = angular.fromJson(data); 16 | var names = {}; 17 | angular.forEach(jsonData, function (item) { 18 | names[item.id] = item.name; 19 | }); 20 | return names; 21 | } 22 | } 23 | }); 24 | }]); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/linked-concept.js: -------------------------------------------------------------------------------- 1 | neonionApp.factory('LinkedConceptService', ['$resource', 2 | function ($resource) { 3 | return $resource('/api/linkedconcepts/:id', 4 | {id: '@id'}, 5 | { 6 | 'save': {method: 'POST', url: '/api/linkedconcepts/'}, 7 | 'update': {method: 'PUT'}, 8 | } 9 | ); 10 | }] 11 | ); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/membership.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Service for memberships 3 | */ 4 | neonionApp.factory('MembershipService', ['$resource', 5 | function ($resource) { 6 | return $resource('/api/memberships/:id', 7 | {id: '@id'}, 8 | { 9 | 'update': {method: 'PUT'} 10 | } 11 | ); 12 | }]); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/property.js: -------------------------------------------------------------------------------- 1 | neonionApp.factory('PropertyService', ['$resource', 2 | function ($resource) { 3 | return $resource('/api/properties/:id', 4 | {id: '@id'}, 5 | { 6 | 'save': {method: 'POST', url: '/api/properties/'}, 7 | 'update': {method: 'PUT'}, 8 | } 9 | ); 10 | }]); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/user.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Service for accounts 3 | */ 4 | neonionApp.factory('UserService', ['$resource', 5 | function ($resource) { 6 | return $resource('/api/users/:id', 7 | {id: '@id'}, 8 | { 9 | 'update': {method: 'PUT'}, 10 | 'current': { 11 | method: 'GET', 12 | params: {}, 13 | cache: true, 14 | isArray: false, 15 | url: '/api/users/current' 16 | } 17 | } 18 | ); 19 | }]); -------------------------------------------------------------------------------- /neonion/static/js/angular/services/workspace.js: -------------------------------------------------------------------------------- 1 | neonionApp.factory('WorkspaceService', ['$http', function ($http) { 2 | "use strict"; 3 | var factory = {}; 4 | 5 | factory.addDocument = function (user, docID) { 6 | return $http.post("api/users/" + user.id + "/add_document", {doc_id: docID}); 7 | }; 8 | 9 | //TODO Create an Endpoint 10 | factory.modifyDocument = function(user, docID) { 11 | return $http.post("api/documents/" + docID + "/modify_document"); 12 | } 13 | 14 | factory.removeDocument = function (user, docID) { 15 | return $http.post("api/users/" + user.id + "/hide_document", {doc_id: docID}); 16 | }; 17 | 18 | return factory; 19 | }]); 20 | -------------------------------------------------------------------------------- /neonion/static/js/neonion-context.jsonld: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "http://www.w3.org/ns/oa-context-20130208.json", 4 | { 5 | "@vocab": "http://www.neonion.org/ontology" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /neonion/static/less/custom-bootstrap.less: -------------------------------------------------------------------------------- 1 | // styleguide:ignore:start// 2 | 3 | /*! 4 | * Bootstrap v3.3.5 (http://getbootstrap.com) 5 | * Copyright 2011-2015 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | */ 8 | 9 | // Core variables and mixins 10 | @import "custom-variables.less"; 11 | @import "../bootstrap/less/mixins.less"; 12 | 13 | // Reset and dependencies 14 | @import "../bootstrap/less/normalize.less"; 15 | @import "../bootstrap/less/print.less"; 16 | @import "../bootstrap/less/glyphicons.less"; 17 | 18 | // Core CSS 19 | @import "../bootstrap/less/scaffolding.less"; 20 | @import "../bootstrap/less/type.less"; 21 | @import "../bootstrap/less/code.less"; 22 | @import "../bootstrap/less/grid.less"; 23 | @import "../bootstrap/less/tables.less"; 24 | @import "../bootstrap/less/forms.less"; 25 | @import "../bootstrap/less/buttons.less"; 26 | 27 | // Components 28 | @import "../bootstrap/less/component-animations.less"; 29 | @import "../bootstrap/less/dropdowns.less"; 30 | @import "../bootstrap/less/button-groups.less"; 31 | @import "../bootstrap/less/input-groups.less"; 32 | @import "../bootstrap/less/navs.less"; 33 | @import "../bootstrap/less/navbar.less"; 34 | @import "../bootstrap/less/breadcrumbs.less"; 35 | @import "../bootstrap/less/pagination.less"; 36 | @import "../bootstrap/less/pager.less"; 37 | @import "../bootstrap/less/labels.less"; 38 | @import "../bootstrap/less/badges.less"; 39 | @import "../bootstrap/less/jumbotron.less"; 40 | @import "../bootstrap/less/thumbnails.less"; 41 | @import "../bootstrap/less/alerts.less"; 42 | @import "../bootstrap/less/progress-bars.less"; 43 | @import "../bootstrap/less/media.less"; 44 | @import "../bootstrap/less/list-group.less"; 45 | @import "../bootstrap/less/panels.less"; 46 | @import "../bootstrap/less/responsive-embed.less"; 47 | @import "../bootstrap/less/wells.less"; 48 | @import "../bootstrap/less/close.less"; 49 | 50 | // Components w/ JavaScript 51 | @import "../bootstrap/less/modals.less"; 52 | @import "../bootstrap/less/tooltip.less"; 53 | @import "../bootstrap/less/popovers.less"; 54 | @import "../bootstrap/less/carousel.less"; 55 | 56 | // Utility classes 57 | @import "../bootstrap/less/utilities.less"; 58 | @import "../bootstrap/less/responsive-utilities.less"; 59 | 60 | // styleguide:ignore:end// -------------------------------------------------------------------------------- /neonion/static/less/modules/colors.less: -------------------------------------------------------------------------------- 1 | // Primary Colors 2 | // 3 | // These are the main color variables. 4 | // Use those variables instead of using CSS HEX values. 5 | // 6 | // @tangerine - Primar Color 7 | // @azure - Secondary color - not used a lot at the moment. 8 | // @red - This is red - used for warnings in forms and notifications. 9 | // @black - Black 10 | // @white - White 11 | // 12 | // markup: 13 | //
{$modifiers}
14 | // 15 | // Styleguide 1.2 16 | 17 | @tangerine: #f39100; // orange 18 | @azure: #008df3; // blue 19 | 20 | @red: #ff3235; // red 21 | @black: #000000; // black 22 | @white: #ffffff; // white 23 | 24 | 25 | // Grey Palette 26 | // 27 | // If you need a shade of grey, choose one of the following 28 | // 29 | // @gallery - Very light grey - used for background of pages and selected 30 | // element in sidebar navigation. 31 | // @silver - Light grey - used for borders e.g: document boxes, tables 32 | // @manatee - Grey - used for hovering borders, disabled buttons or 33 | // navigation elements. 34 | // @dove-gray - Dark grey - used as border color for textinput. 35 | // @mid-gray - Dark dark grey - used as floating label color and placeholder. 36 | // @ship-gray - Dark dark dark grey - general text color on document boxes, 37 | // buttons, links, navigation, subnavigation things which can be 38 | // hovered in general. 39 | // 40 | // markup: 41 | //
{$modifiers}
42 | // 43 | // Styleguide 1.1 44 | 45 | @gallery: #eeeeee; // light-grey 46 | @silver: #cdcdcd; // grey 47 | @manatee: #8e8e93; // dark-grey 48 | @dove-gray: #717171; // dark-dark-grey 49 | @mid-gray: #616165; // dark-dark-dark-grey 50 | @ship-gray: #434346; // dark-dark-dark-dark-grey -------------------------------------------------------------------------------- /neonion/static/less/modules/variables.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | // 3 | // This section descibes used variables. 4 | // 5 | // @lh - Vertical Gap (top to bottom) - Line Height, using the one from 6 | // bootstrap, it is about 20px. Is is like a vertical grid. 7 | // @gap-h - Horizontal Gap (left to right) - Using the one from bootstrap, it 8 | // is 12px. It is used for horizontal gaps. 9 | // 10 | // markup: 11 | //
LESS variable
12 | // 13 | // Styleguide 4.1 14 | @lh: @line-height-computed; 15 | @gap-h: @padding-base-horizontal; -------------------------------------------------------------------------------- /neonion/static/less/partials/buttons.less: -------------------------------------------------------------------------------- 1 | // Buttons 2 | // 3 | // We are using the same buttons as in bootstrap, look [here](http://getbootstrap.com/css/#buttons). 4 | // Buttons can also be styled as links. 5 | // We added a `btn-secondary` for grey buttons on white background used in the annotator. 6 | // `btn-xs` from bootstrap can also be used. 7 | // 8 | // .btn-default - Used for not primary action (e.g. cancel) on grey bg. 9 | // .btn-primary - Used for primary action (e.g. save). 10 | // .btn-secondary - Used for buttons on white background (e.g. in annotator). 11 | // .btn-link - Deemphasize buttons (e.g. delete). 12 | // 13 | // markup: 14 | // Button 15 | // 16 | // 17 | // button with an icon 18 | // 19 | // 20 | // 21 | // Styleguide 3.7 22 | 23 | .btn-secondary { 24 | .button-variant(@btn-secondary-color; @btn-secondary-bg; @btn-secondary-border); 25 | } 26 | 27 | // Size and Spacing 28 | // 29 | // Sometimes buttons need to be smaller, e.g in annotator. 30 | // And also need to have some spacing around them, so when having multiple 31 | // buttons below each other they dont stick together. 32 | // 33 | // .btn-xs - Extra small buttons. 34 | // .btn-spacing - Add some extra spacing around them. 35 | // 36 | // markup: 37 | // Button
38 | // Button
39 | // Button 40 | // 41 | // Styleguide 3.7.1 42 | .btn-spacing { 43 | margin: @gap-h/4; 44 | } -------------------------------------------------------------------------------- /neonion/static/less/partials/helper.less: -------------------------------------------------------------------------------- 1 | // Vertical Spacing - Helper Classes 2 | // TODO Styleguide 3 | .gap-bottom { 4 | margin-bottom: @lh; 5 | } 6 | 7 | .gap-top { 8 | margin-top: @lh; 9 | } 10 | 11 | .annotator-font { 12 | font-family: 'Lato', sans-serif; 13 | font-weight: 300; 14 | } 15 | 16 | .annotator-basefontsize { 17 | font-size: @font-size-base - 2px; 18 | line-height: @lh; 19 | } 20 | 21 | // https://medium.com/@Florian/freebie-google-material-design-shadow-helper-2a0501295a2d 22 | .shadow { 23 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 24 | } -------------------------------------------------------------------------------- /neonion/static/less/partials/links.less: -------------------------------------------------------------------------------- 1 | // Links 2 | // 3 | // A link can be explicitly styled as a link. 4 | // 5 | // markup: 6 | // this is a link with class link
7 | // this is a link 8 | // 9 | // Styleguide 3.8 10 | .link { 11 | text-decoration: underline; 12 | &:hover { color: darken(@tangerine, 2%); } 13 | } -------------------------------------------------------------------------------- /neonion/static/partials/accounts-user-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 39 | 45 | 46 | 47 |
UserAccount Settings
{{ user.email }} 13 | 38 | 40 | 44 |
-------------------------------------------------------------------------------- /neonion/static/partials/analyze-query.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 | 16 |
17 | 18 |
19 | 20 | 26 |
27 | 28 |
29 | 30 | 36 |
37 |
38 | 39 |
40 | 41 |
{{ form.prefixes }}
42 |
43 |
44 | 45 | 49 |
50 | 51 |
52 |
53 |
54 |
-------------------------------------------------------------------------------- /neonion/static/partials/annotation-list.html: -------------------------------------------------------------------------------- 1 |
2 | 14 |
15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 |
-------------------------------------------------------------------------------- /neonion/static/partials/annotations/annotation-document-list.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /neonion/static/partials/annotations/annotation-occurrence-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
Annotation ContextDocumentCreated
{{ annotation.neonion.context.surrounding.left }} {{ annotation.quote }} {{ annotation.neonion.context.surrounding.right }} {{ documentTitles[annotation.uri] }} {{ annotation.created | date : "MM/dd/yyyy 'at' h:mma" }}
-------------------------------------------------------------------------------- /neonion/static/partials/annotations/comment-list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 9 |
10 |
11 |
12 |

13 | 14 | {{ documentTitles[documentKey] }} 15 | 16 | {{ groupNames[groupKey] }} 17 | 18 | 19 | Private 20 | 21 |

22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 40 | 41 | 43 | 44 | 45 |
ContextCommentCreated by
33 | {{ annotation.neonion.context.surrounding.left | truncate:'left' }} 34 | 36 | {{ annotation.quote }}  37 | 38 | {{ annotation.neonion.context.surrounding.right | truncate:'right' }} 39 | {{ annotation.text }}{{ annotation['neonion']['creator'] }}
{{ annotation.created | date : "MM/dd/yyyy 'at' h:mma" }} 42 |
46 |
47 |
48 |
-------------------------------------------------------------------------------- /neonion/static/partials/annotations/concept-list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 8 |
9 |
10 |

11 | {{ (annotationByConceptType | first)['neonion']['viewer']['conceptLabel'] }} 12 |

13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 33 | 34 | 35 | 36 |
Concept NameDetailsLast Created
{{ (annotationByConcept | first)['oa']['hasBody']['label'] }} 25 | 26 | {{ annotationByConcept.length }} Occurrences 27 | 28 | in 29 | 30 | {{ (annotationByConcept | unique : 'uri').length }} Documents 31 | 32 | {{ (annotationByConcept | last).created | date : "MM/dd/yyyy 'at' h:mma" }}
37 |
38 |
-------------------------------------------------------------------------------- /neonion/static/partials/annotations/highlight-list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 9 |
10 |
11 |
12 |

13 | 14 | {{ documentTitles[documentKey] }} 15 | 16 | {{ groupNames[groupKey] }} 17 | 18 | 19 | Private 20 | 21 |

22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 39 | 41 | 42 | 43 |
HighlightCreated by
32 | {{ annotation.neonion.context.surrounding.left | truncate:'left' }} 33 | 35 | {{ annotation.quote }}  36 | 37 | {{ annotation.neonion.context.surrounding.right | truncate:'right' }} 38 | {{ annotation['neonion']['creator'] }}
{{ annotation.created | date : "MM/dd/yyyy 'at' h:mma" }} 40 |
44 |
45 |
46 |
-------------------------------------------------------------------------------- /neonion/static/partials/annotator/annotator-context.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • 3 | 7 | 8 |
  • 9 |
  • 10 | 14 | 15 |
  • 16 |
  • 17 | 18 |
  • 19 |
20 |
21 | {{ document.title }} 22 | 23 | Private 24 | {{ group.name }} 25 | 26 |
27 | -------------------------------------------------------------------------------- /neonion/static/partials/annotator/annotator.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 |
15 |
-------------------------------------------------------------------------------- /neonion/static/partials/generic-resource-list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 9 |
10 |
11 |
12 |
13 |
14 |
15 | 23 |
24 |
26 |
27 |

28 | 29 | 30 |

31 | 32 |

34 | 35 |

36 |
37 |
38 |
39 |
40 |
41 |
42 | 43 |
-------------------------------------------------------------------------------- /neonion/static/partials/import-meta-data.html: -------------------------------------------------------------------------------- 1 |

Document properties

2 |

Please choose the properties you want to consider for this document,
which correspond to the Dublin Core Metadata Element Set

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 25 | 26 | 27 | 28 |
PropertyDefinitionEntry
{{ key }}{{ value.definition }} 19 |
20 | 23 |
24 |
29 | -------------------------------------------------------------------------------- /neonion/static/partials/meta_data_in_properties.html: -------------------------------------------------------------------------------- 1 |

Please choose the properties you want to consider for your documents
which correspond to the Dublin Core Metadata Element Set

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 |
ChosenPropertyDefinition
14 | 17 | {{ key }}{{ value.definition }}
-------------------------------------------------------------------------------- /neonion/static/partials/vocabulary/concept-detail.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | 9 | 12 | 15 | 18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 | 27 |
28 |
29 |
30 |
31 | 32 | 34 |
35 |
36 |
37 |
38 |
39 |
40 | 41 | 44 |
45 |
46 |
47 | 48 |
49 |
-------------------------------------------------------------------------------- /neonion/static/partials/vocabulary/conceptset-detail.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | 9 | 12 | 15 | 18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 | 27 |
28 |
29 |
30 |
31 | 32 | 34 |
35 |
36 |
37 |
38 |
39 |
40 | 41 | 44 |
45 |
46 |
47 | 48 |
49 |
-------------------------------------------------------------------------------- /neonion/static/partials/vocabulary/multiselect.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 |
8 |
    9 |
  • 11 | 12 | {{ item.label }} 13 |

    {{ item.comment }}

    14 |
  • 15 |
  • {{ literals.multiselect.nothingAssigned }}
  • 16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 | 27 |
28 |
29 |
30 |
31 |
    32 |
  • 34 | 35 | {{ item.label }} 36 |

    {{ item.comment }}

    37 |
  • 38 |
  • {{ literals.multiselect.nothingAssignable }}
  • 39 |
40 |
41 |
-------------------------------------------------------------------------------- /neonion/static/partials/workbench/elasticsearch.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | Bulk Import 6 |
7 | 8 | 10 |
11 |
12 | 13 | 15 |
16 |
17 | 18 | 20 |
21 |
22 | 24 | 26 |
27 |
28 |
30 | {{ form.upload.progress }}% 31 |
32 |
33 |
34 |
35 |
36 |
37 |
-------------------------------------------------------------------------------- /neonion/static/partials/workbench/orphaned-annotation-list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | DocumentIdentifer {{ key }} 4 | 5 |
6 | 13 |
-------------------------------------------------------------------------------- /neonion/static/partials/workspace-document-list.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ workspace.name }}

3 | Import to Workspace 4 | 5 | 12 |
13 | -------------------------------------------------------------------------------- /neonion/static/utils/additional.less: -------------------------------------------------------------------------------- 1 | .myfont { 2 | font-family: 'Lato', sans-serif; 3 | font-weight: 300; 4 | font-size: 18px; 5 | } 6 | 7 | .grey-bg { 8 | background-color: @gallery; 9 | } 10 | 11 | .half-size { 12 | width: 50%; 13 | } 14 | 15 | .margin { 16 | padding: @lh !important; 17 | } -------------------------------------------------------------------------------- /neonion/static/utils/styleguide.scss: -------------------------------------------------------------------------------- 1 | // Main color definitions 2 | $primary-color: #434346 !default; // @ship-gray: dark-dark-dark-dark-grey 3 | $secondary-color: #cdcdcd !default; // @silver: grey 4 | $tertiary-color: #cdcdcd !default; // @silver: grey 5 | 6 | // Button and link colors 7 | $primary-action-color: #f39100 !default; // @tangerine: orange 8 | $default-action-color: #f39100 !default; // @tangerine: orange 9 | $action-color-change: 15% !default; -------------------------------------------------------------------------------- /neonion/templates/accounts_management.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Accounts{% endblock %} 6 | {% block page_id %}userlist{% endblock %} 7 | 8 | {% block content %} 9 |
10 | 18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 |
28 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/annotator.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | {% load pipeline %} 5 | 6 | {% block title %}Annotator{% endblock %} 7 | {% block page_id %}annotator{% endblock %} 8 | 9 | {% block left %} 10 | 15 | {% endblock %} 16 | 17 | {% block right %} 18 |
19 |
20 |
21 | {% block header %} 22 | 23 | {% endblock %} 24 |
25 |
26 | 27 |
28 |
29 |
30 | {% endblock %} 31 | 32 | {% block content %} 33 | {% endblock %} 34 | 35 | {% block scripts %} 36 | {% javascript 'annotator' %} 37 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/base_annotations.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Annotations{% endblock %} 6 | {% block page_id %}Annotations{% endblock %} 7 | 8 | {% block content %} 9 |
10 | 11 |
12 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/base_annotations_documents.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Documents{% endblock %} 6 | {% block page_id %}Documents{% endblock %} 7 | 8 | {% block content %} 9 | 10 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/base_annotations_occurrences.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}All Occurrences{% endblock %} 6 | {% block page_id %}allOccurrences{% endblock %} 7 | 8 | {% block content %} 9 | 10 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/base_modify.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Modify Document Meta Data{% endblock %} 6 | {% block page_id %}Modify Document Meta Data{% endblock %} 7 | 8 | {% block content %} 9 | 10 | 28 |
    29 | {% for error in errors %} 30 |
  • {{error}}
  • 31 | {% endfor %} 32 |
33 |
34 |
35 | {% csrf_token %} 36 | 37 |
38 | 39 |
40 |
41 |
42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /neonion/templates/base_settings.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Settings{% endblock %} 6 | {% block page_id %}settings{% endblock %} 7 | 8 | {% block content %} 9 |
10 | 17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/base_vocabulary.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Vocabulary{% endblock %} 6 | {% block page_id %}vocabulary{% endblock %} 7 | 8 | {% block content %} 9 |
10 | 22 | 23 |
24 |
25 | 28 |
29 |
30 | 33 |
34 |
35 | 38 |
39 |
40 | 41 |
42 | {% endblock %} 43 | 44 | {% block scripts %} 45 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/query.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Query{% endblock %} 6 | 7 | {% block content %} 8 | 9 | {% endblock %} 10 | 11 | {% block scripts %} 12 | 13 | 14 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/workbench.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Workbench{% endblock %} 6 | {% block page_id %}workbench{% endblock %} 7 | 8 | {% block content %} 9 |
10 | 18 | 19 |
20 |
21 | 24 |
25 |
26 | 27 |
28 |
29 |
30 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templates/workspace.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | {% block title %}Documents{% endblock %} 6 | 7 | {% block content %} 8 |
9 | 21 |
22 |
23 | 27 |
28 |
29 | 33 |
34 |
35 | 39 |
40 |
41 |
42 | {% endblock %} -------------------------------------------------------------------------------- /neonion/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/neonion/templatetags/__init__.py -------------------------------------------------------------------------------- /neonion/templatetags/custom_filters.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from django import template 4 | from django.utils.html import mark_safe 5 | 6 | register = template.Library() 7 | 8 | 9 | @register.filter 10 | def toJSON(value): 11 | return mark_safe(json.dumps(value)) 12 | -------------------------------------------------------------------------------- /neonion/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from django.core.urlresolvers import reverse 3 | from accounts.tests import create_test_user 4 | from documents.tests import create_test_document 5 | from neonion import views 6 | 7 | 8 | class ViewTestCase(TestCase): 9 | 10 | def setUp(self): 11 | # create test user 12 | self.test_user = create_test_user() 13 | 14 | # create test document 15 | self.test_document = create_test_document() 16 | 17 | def test_neonion_views(self): 18 | self.assertTrue(self.client.login(email='test@neonin.org', password='tester')) 19 | 20 | # annotator - success 21 | response = self.client.get(reverse(views.render_annotator, args=[self.test_document.id])) 22 | self.assertEqual(response.status_code, 200) 23 | 24 | # annotator - fail 25 | response = self.client.get(reverse(views.render_annotator, args=[-1])) 26 | self.assertEqual(response.status_code, 404) 27 | 28 | # home 29 | response = self.client.get(reverse(views.render_home)) 30 | self.assertEqual(response.status_code, 200) 31 | 32 | # my annotations 33 | response = self.client.get(reverse(views.annotations)) 34 | self.assertEqual(response.status_code, 200) 35 | 36 | # accounts 37 | response = self.client.get(reverse(views.accounts_management)) 38 | self.assertEqual(response.status_code, 200) 39 | 40 | # query 41 | response = self.client.get(reverse(views.render_query)) 42 | self.assertEqual(response.status_code, 200) 43 | 44 | # import 45 | response = self.client.get(reverse(views.import_document)) 46 | self.assertEqual(response.status_code, 200) 47 | 48 | # settings 49 | response = self.client.get(reverse(views.render_settings)) 50 | self.assertEqual(response.status_code, 200) -------------------------------------------------------------------------------- /neonion/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from django.contrib import admin 3 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns 4 | 5 | admin.autodiscover() 6 | 7 | urlpatterns = [ 8 | url(r'^$', 'neonion.views.render_home'), 9 | url(r'^annotations/$', 'neonion.views.annotations'), 10 | url(r'^annotation_occurrences$', 'neonion.views.annotation_occurrences'), 11 | url(r'^annotation_documents$', 'neonion.views.annotation_documents'), 12 | url(r'^import/$', 'neonion.views.import_document'), 13 | url(r'^modify/(?P.+)$', 'neonion.views.modify_document'), 14 | url(r'^vocabulary/$', 'neonion.views.render_vocabulary'), 15 | url(r'^settings/$', 'neonion.views.render_settings'), 16 | url(r'^query$', 'neonion.views.render_query'), 17 | url(r'^workbench$', 'neonion.views.render_workbench'), 18 | 19 | url(r'^management/?$', 'neonion.views.accounts_management'), 20 | 21 | url(r'^annotator/(?P.+)/(?P.+)$', 'neonion.views.render_annotator'), 22 | 23 | url(r'^api/', include('api.urls')), 24 | url(r'^store/', include('store.urls')), 25 | url(r'^accounts/', include('accounts.urls')), 26 | url(r'^documents/', include('documents.urls')), 27 | url(r'^endpoint/', include('endpoint.urls')), 28 | 29 | # wikidata application 30 | url(r'^wikidata/', include('wikidata.urls')), 31 | 32 | 33 | # Django rest 34 | url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) 35 | ] 36 | 37 | urlpatterns += staticfiles_urlpatterns() 38 | #urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 39 | -------------------------------------------------------------------------------- /neonion/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.shortcuts import render_to_response 3 | from django.template import RequestContext 4 | from django.contrib.auth.decorators import login_required 5 | from documents.models import Document 6 | from django.shortcuts import get_object_or_404 7 | 8 | 9 | # Create your views here. 10 | @login_required 11 | def render_home(request): 12 | return render_to_response('workspace.html', context_instance=RequestContext(request)) 13 | 14 | 15 | @login_required 16 | def render_annotator(request, group_pk, document_pk): 17 | get_object_or_404(Document, id=document_pk) 18 | 19 | data = { 20 | 'group_pk': group_pk, 21 | 'document_pk': document_pk, 22 | } 23 | return render_to_response('annotator.html', data, context_instance=RequestContext(request)) 24 | 25 | 26 | @login_required 27 | def annotations(request): 28 | return render_to_response('base_annotations.html', context_instance=RequestContext(request)) 29 | 30 | 31 | @login_required 32 | def annotation_occurrences(request): 33 | return render_to_response('base_annotations_occurrences.html', context_instance=RequestContext(request)) 34 | 35 | 36 | @login_required 37 | def annotation_documents(request): 38 | return render_to_response('base_annotations_documents.html', context_instance=RequestContext(request)) 39 | 40 | 41 | @login_required 42 | def render_vocabulary(request): 43 | return render_to_response('base_vocabulary.html', context_instance=RequestContext(request)) 44 | 45 | 46 | @login_required 47 | def render_settings(request): 48 | return render_to_response('base_settings.html', context_instance=RequestContext(request)) 49 | 50 | 51 | @login_required 52 | def accounts_management(request): 53 | return render_to_response('accounts_management.html', context_instance=RequestContext(request)) 54 | 55 | 56 | @login_required 57 | def render_query(request): 58 | return render_to_response('query.html', context_instance=RequestContext(request)) 59 | 60 | 61 | @login_required 62 | def render_workbench(request): 63 | return render_to_response('workbench.html', context_instance=RequestContext(request)) 64 | 65 | 66 | @login_required 67 | def import_document(request): 68 | return render_to_response('base_import.html', context_instance=RequestContext(request)) 69 | 70 | @login_required 71 | def modify_document(request,document_pk): 72 | if Document.objects.filter(id=document_pk).exists(): 73 | document = Document.objects.get(id=document_pk) 74 | return render_to_response('base_modify.html', context_instance=RequestContext(request, {"doc_id" : document_pk,"doc" : document})) 75 | return render_to_response("/",context_instance=RequestContext(request)) 76 | 77 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.8.19 2 | djangorestframework==3.2.3 3 | django-pipeline==1.5.1 4 | requests==2.20.0 5 | elasticsearch==6.0.0 6 | enum34==1.0.4 7 | SPARQLWrapper==1.6.4 8 | beautifulsoup4==4.3.2 9 | pywikibot==3.0.20180204 10 | six==1.10.0 11 | packaging==16.8 12 | appdirs==1.4.3 13 | -------------------------------------------------------------------------------- /settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/settings/__init__.py -------------------------------------------------------------------------------- /settings/demo.py: -------------------------------------------------------------------------------- 1 | from settings.default import * 2 | 3 | # neonion specific 4 | DEFAULT_USER_ACTIVE_STATE = True 5 | ELASTICSEARCH_INDEX = "neonion-demo" -------------------------------------------------------------------------------- /settings/development.py: -------------------------------------------------------------------------------- 1 | from settings.default import * 2 | 3 | # neonion specific 4 | DEFAULT_USER_ACTIVE_STATE = True 5 | 6 | # # settings for serialization to triple store 7 | # ENDPOINT_ENABLED = False 8 | # ENDPOINT = 'http://localhost:8080/openrdf-sesame/repositories/neonion' 9 | # ENDPOINT_UPDATE = 'http://localhost:8080/openrdf-sesame/repositories/neonion/statements' 10 | # 11 | # # settings for NER service 12 | # NER_SERVICE_ENABLED = False 13 | # NER_SERVICE_URL = 'http://localhost:5000' 14 | 15 | # set environment 16 | DEBUG = True 17 | -------------------------------------------------------------------------------- /settings/docker.py: -------------------------------------------------------------------------------- 1 | # neonion specific 2 | DEFAULT_USER_ACTIVE_STATE = True 3 | -------------------------------------------------------------------------------- /settings/production.py: -------------------------------------------------------------------------------- 1 | from settings.default import * 2 | 3 | STATIC_ROOT = "/var/www/neonion/static/" 4 | 5 | # neonion specific 6 | DEFAULT_USER_ACTIVE_STATE = False 7 | -------------------------------------------------------------------------------- /settings/test.py: -------------------------------------------------------------------------------- 1 | # neonion specific 2 | DEFAULT_USER_ACTIVE_STATE = True 3 | -------------------------------------------------------------------------------- /store/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/store/__init__.py -------------------------------------------------------------------------------- /store/decorators.py: -------------------------------------------------------------------------------- 1 | from accounts.models import WorkingGroup 2 | from documents.models import Document 3 | from django.http import HttpResponseForbidden 4 | 5 | 6 | def require_group_permission(view_func, group_key='group_pk', document_key='document_pk'): 7 | """Requires user membership in the groups passed in.""" 8 | def _decorated(view, request, *args, **kwargs): 9 | # check if the group is not private 10 | if kwargs[group_key] != request.user.email: 11 | group = WorkingGroup.objects.get(pk=kwargs[group_key]) 12 | document = Document.objects.get(pk=kwargs[document_key]) 13 | 14 | # check if the user is entitled in the group and the group contains the document 15 | if request.user in group.members.all() and document in group.documents.all(): 16 | return view_func(view, request, *args, **kwargs) 17 | else: 18 | return HttpResponseForbidden() 19 | else: 20 | return view_func(view, request, *args, **kwargs) 21 | 22 | return _decorated 23 | -------------------------------------------------------------------------------- /store/logging/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/store/logging/__init__.py -------------------------------------------------------------------------------- /store/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from store import views 3 | 4 | urlpatterns = [ 5 | # AnnotationStore API 6 | url(r'^$', 'store.views.root'), 7 | url(r'^search$', 'store.views.search'), 8 | 9 | url(r'^(?P.+)/(?P.+)/annotations$', views.AnnotationListView.as_view()), 10 | url(r'^(?P.+)/(?P.+)/annotations/(?P.+)$', views.AnnotationDetailView.as_view()), 11 | url(r'^(?P.+)/(?P.+)/search$', views.SearchView.as_view()), 12 | ] 13 | -------------------------------------------------------------------------------- /wikidata/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FUB-HCC/neonion/f2007a7cde80cf8ed93d64f870aef9b2d0bd1bde/wikidata/__init__.py -------------------------------------------------------------------------------- /wikidata/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /wikidata/static/js/annotator/annotator.neonion.wikidata.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | 5 | Annotator.Plugin.neonion.prototype.widgets['wikidataLiveEntitySearch'] = function (scope, options) { 6 | var factory = {}; 7 | 8 | factory.load = function () { 9 | 10 | // overwrite local endpoint called for entity search 11 | scope.options.lookup = { 12 | prefix: '/wikidata', 13 | urls: { 14 | search: "/itemsearch" 15 | } 16 | }; 17 | 18 | scope.annotator.subscribe('annotationEditorShown', function (editor, annotation) { 19 | 20 | console.log(annotation); 21 | console.log(scope.options); 22 | 23 | }); 24 | 25 | scope.annotator.subscribe('annotationEditorHidden', function () { 26 | 27 | 28 | }); 29 | 30 | }; 31 | 32 | return factory; 33 | 34 | } 35 | })(); 36 | -------------------------------------------------------------------------------- /wikidata/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | 4 | urlpatterns = [ 5 | url(r'^itemsearch/(?P.*)/(?P.*)/(?P.*)$', 'wikidata.views.search_typed_items'), 6 | ] 7 | -------------------------------------------------------------------------------- /wsgi_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for neonion project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | from django.core.wsgi import get_wsgi_application 12 | 13 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.demo") 14 | 15 | application = get_wsgi_application() 16 | -------------------------------------------------------------------------------- /wsgi_dev.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for neonion project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | from django.core.wsgi import get_wsgi_application 12 | 13 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.development") 14 | 15 | application = get_wsgi_application() 16 | -------------------------------------------------------------------------------- /wsgi_production.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for neonion project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | from django.core.wsgi import get_wsgi_application 12 | 13 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.production") 14 | 15 | application = get_wsgi_application() -------------------------------------------------------------------------------- /wsgi_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for neonion project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | from django.core.wsgi import get_wsgi_application 12 | 13 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.test") 14 | 15 | application = get_wsgi_application() 16 | --------------------------------------------------------------------------------