Skip to content
Snippets Groups Projects
Commit 1707c174 authored by Becker, Benjamin's avatar Becker, Benjamin
Browse files

Merge pull request #55 in TPSH/ckanext-odsh from dev to master

* commit '982c0e4c': (60 commits)
  adds README
  fixes bug in footer.html
  fixes bug, date in filter list was invisible in IE
  fixes margin in password reset form
  adds aria role menuitem to user dropdown menu
  improves accessibility
  adds alt-text and aria-hidden to category items in search results
  adds skiplink, adds empty alternative text to category items
  bugfix thumbnail to many values
  bugfix tools
  replaces dict by OrderedDict for SUBJECT_MAPPING, adds tests
  adds unit tests for get_subject_for_selection
  changed req
  fixes import bug
  fixes bug in css introduced by commit  64813bcd
  new
  changed to pdftotext
  minor changes, code style
  changed thumbnail
  css
  ...
parents 7a227c6c 982c0e4c
No related branches found
No related tags found
No related merge requests found
Showing
with 532 additions and 120 deletions
# ckanext-odsh
Diese CKAN-Extension enthält die wichtigsten Features und das Layout für das Tranzparenzportal Schleswig-Holstein.
Sie ist eine Weiterentwicklung der gleichnamigen Extension, die im Zuge der Entwicklung des Open Data Portals Schleswig-Holstein entwickelt wurde.
## Branches
### master
Dieser Branch enthält den aktuell auf den Stage- bzw. Prod-Servern laufenden Code.
### dev
Dieser Branch enthält den aktuellsten Stand mit allen fertig entwickelten Features.
### andere Branches
Für die Entwicklung neuer Features soll jeweils ein eigener Branch vom dev-Branch abgezweigt werden. Für den Branch soll ein sprechender Name gewählt werden.
## Deployment auf Produktivsystem
Das Deployment auf das Produktivsystem geschieht über Ansible. Die dafür benötigten Skripte befinden sich im Repository `tpsh_deploy`.
## Manuelle Installation
## Konfiguration
Die Extension benötigt Konfigurationsparameter in der CKAN-Konfigurationsdatei (z.B. `production.ini`). Die korrekten Parameter für das Produktivsystem befinden sich im Repository `tpsh_deploy` unter `resources/production.ini`. Folgende Parameter sollten für Enwicklungssysteme geändert werden:
| Parameter | Erläuterung | Wert für Entwicklungssysteme |
|---------------------------------------|---------------------------------------------------------------|-------------------------------------------|
| ckanext.odsh.use_matomo | `true` schaltet das matomo-Tracking ein. | `false` |
| ckanext.odsh.skip_icap_virus_check | `false` schaltet den Virus-Check ein. | `true` |
| ckanext.odsh.showtestbanner | `true` schaltet das Banner "Testsystem" ein, Muss `false` für Production-Server sein. | - |
\ No newline at end of file
"use strict";
function isPasswordValid(password) {
if (password.length == 0) return true;
var minimumLength = 8;
var isValid =
(password.length >= minimumLength) &&
(atLeastOneUpperCaseLetter(password)) &&
(atLeastOneLowerCaseLetter(password)) &&
(atLeastOneNoneLetter(password));
return isValid
function atLeastOneUpperCaseLetter(password) {
return (password !== password.toLowerCase())
}
function atLeastOneLowerCaseLetter(password) {
return (password !== password.toUpperCase())
}
function atLeastOneNoneLetter(password) {
return /[\W\d_]/.test(password)
}
}
function showPasswordStatus(isValid, inputElement) {
if (isValid) {
messageText = '';
} else {
messageText = 'Passwörter müssen länger als 8 Zeichen sein und Großbuchstaben, Kleinbuchstaben und andere Zeichen enthalten.'
}
get_error_element(inputElement).innerHTML = messageText;
function get_error_element(inputElement) {
// assumes that there is an element after input_element's parent that
// contains a class "inline-error"
var currentNode = inputElement.parentNode
do {
currentNode = currentNode.nextElementSibling;
} while (
(currentNode !== null) &&
!(currentNode.classList.contains('inline-error'))
)
return currentNode
}
}
function setSubmitButtonState(isPasswordValid) {
var submitButton = document.getElementsByName('save')[0];
submitButton.disabled = !isPasswordValid;
}
ckan.module('tpsh_validate_password', function ($) {
return {
initialize: function () {
$.proxyAll(this, /_on/);
this.el.on('input', this._onChange);
},
_onChange: function(event) {
var inputElement = event.target;
var newPassword = inputElement.value;
var isValid = isPasswordValid(newPassword);
showPasswordStatus(isValid, inputElement);
setSubmitButtonState(isValid);
}
};
});
\ No newline at end of file
...@@ -72,10 +72,10 @@ ...@@ -72,10 +72,10 @@
<div class="error-body"><h2>Seite nicht gefunden</h2> <div class="error-body"><h2>Seite nicht gefunden</h2>
<h3>Wie finde ich die gesuchten Inhalte im Landesportal?</h3> <h3>Wie finde ich die gesuchten Inhalte im Landesportal?</h3>
<p><a class="" href="http://www.schleswig-holstein.de/tpstart" title="Zur Startseite">Zur Startseite des Open-Data-Portals</a></p> <p><a class="" href="http://www.schleswig-holstein.de/tpstart" title="Zur Startseite">Zur Startseite des Transparenzportals</a></p>
<h3>Kontakt</h3> <h3>Kontakt</h3>
<p>Bei Fragen oder Problemen mit dem Open-Data-Portal schicken Sie bitte eine E-Mail an die Adresse opendata@lr.landsh.de oder verwenden das Kontaktformular:</p> <p>Bei Fragen oder Problemen mit dem Transparenzportal schicken Sie bitte eine E-Mail an die Adresse transparenz@lr.landsh.de oder verwenden das Kontaktformular:</p>
<p><a class="" href="https://www.schleswig-holstein.de/tpkontakt" title="Kontakt">Zum Kontaktformular</a></p> <p><a class="" href="https://www.schleswig-holstein.de/tpkontakt" title="Kontakt">Zum Kontaktformular</a></p>
</div> </div>
</div> </div>
......
# encoding: utf-8
import csv import csv
import datetime import datetime
import logging import logging
...@@ -5,6 +7,7 @@ from string import lower ...@@ -5,6 +7,7 @@ from string import lower
import json import json
import re import re
import urllib2 import urllib2
from collections import OrderedDict
from ckan.common import config from ckan.common import config
import ckan.lib.helpers as helpers import ckan.lib.helpers as helpers
...@@ -99,9 +102,12 @@ def load_language_mapping(): ...@@ -99,9 +102,12 @@ def load_language_mapping():
LANGUAGE_MAPPING = json.loads(language_mapping_json.read()) LANGUAGE_MAPPING = json.loads(language_mapping_json.read())
return LANGUAGE_MAPPING return LANGUAGE_MAPPING
def load_json_to_ordered_dict(json_str):
return json.loads(json_str, object_pairs_hook=OrderedDict)
def load_subject_mapping(): def load_subject_mapping():
with open(config.get('ckanext.odsh.subject_mapping')) as subject_mapping_json: with open(config.get('ckanext.odsh.subject_mapping')) as subject_mapping_json:
SUBJECT_MAPPING = json.loads(subject_mapping_json.read()) SUBJECT_MAPPING = load_json_to_ordered_dict(subject_mapping_json.read())
return SUBJECT_MAPPING return SUBJECT_MAPPING
def get_language_of_package(pkg_dict): def get_language_of_package(pkg_dict):
...@@ -177,3 +183,29 @@ def get_resource_size(resource): ...@@ -177,3 +183,29 @@ def get_resource_size(resource):
resource_size = resource.get('size') resource_size = resource.get('size')
if resource_size: if resource_size:
return size_of_fmt(resource_size) return size_of_fmt(resource_size)
def get_address_org(organization):
list_extras = organization.get('extras')
address = dict()
if not list_extras:
return address
for extra in list_extras:
address.update({extra.get('key'):extra.get('value')})
web = address.get('web')
if web and not web.startswith('http'):
web = 'http://' + web
address.update({'web':web})
return address
def get_body_mail(organization, package):
package_name = package.get('name')
url = helpers.url_for(controller='package', action='read', id=package_name, qualified = True)
title = package.get('title')
anrede = "Sehr geehrte Damen und Herren," + "%0D%0A" + "%0D%0A" + "zu folgendem Eintrag habe ich eine Anmerkung/Frage:" + "%0D%0A" + "%0D%0A"
mail_titel = "Titel: " + title + "%0D%0A"
mail_document = "Dokument-ID: " + package_name + "%0D%0A"
mail_url = "URL: " + url + "%0D%0A" + "%0D%0A"
message = mail_titel + mail_document + mail_url + "Mein Kommentar:" + "%0D%0A" + "%0D%0A" + "%0D%0A" + "%0D%0A"
return anrede + message
\ No newline at end of file
No preview for this file type
...@@ -348,10 +348,10 @@ msgid "Score" ...@@ -348,10 +348,10 @@ msgid "Score"
msgstr "Open-Data-Eigenschaften" msgstr "Open-Data-Eigenschaften"
msgid "Issued Ascending" msgid "Issued Ascending"
msgstr "Veröffentlichungsdatum aufsteigend" msgstr "Veröffentlichungsdatum: Älteste zuerst"
msgid "Issued Descending" msgid "Issued Descending"
msgstr "Veröffentlichungsdatum absteigend" msgstr "Veröffentlichungsdatum: Neueste zuerst"
msgid "Name Resource" msgid "Name Resource"
msgstr "Name Ressource" msgstr "Name Ressource"
...@@ -488,17 +488,18 @@ msgstr "Enddatum" ...@@ -488,17 +488,18 @@ msgstr "Enddatum"
msgid "main nav menu" msgid "main nav menu"
msgstr "Navigations-Hauptmenü" msgstr "Navigations-Hauptmenü"
msgid "Start Date Ascending"
msgstr "Startdatum aufsteigend"
msgid "Start Date Descending" msgid "Start Date Descending"
msgstr "Starttdatum absteigend" msgstr "Startdatum: Neueste zuerst"
msgid "End Date Ascending" msgid "Start Date Ascending"
msgstr "Enddatum aufsteigend" msgstr "Startdatum: Älteste zuerst"
msgid "End Date Descending" msgid "End Date Descending"
msgstr "Enddatum absteigend" msgstr "Enddatum: Neueste zuerst"
msgid "End Date Ascending"
msgstr "Enddatum: Älteste zuerst"
msgid "send an email" msgid "send an email"
msgstr "E-Mail senden" msgstr "E-Mail senden"
...@@ -535,3 +536,9 @@ msgstr[1] "Kategorien:" ...@@ -535,3 +536,9 @@ msgstr[1] "Kategorien:"
msgid "Publisher" msgid "Publisher"
msgstr "Herausgeber" msgstr "Herausgeber"
msgid "Name Ascending"
msgstr "Name: A – Z"
msgid "Name Descending"
msgstr "Name: Z – A"
\ No newline at end of file
import logging import logging
import ckan.logic as logic
from ckan.logic.action.update import user_update
from ckan.logic.action.create import package_create, user_create, group_member_create from ckan.logic.action.create import package_create, user_create, group_member_create
import ckan.model as model import ckan.model as model
import ckan.lib.dictization.model_dictize as model_dictize import ckan.lib.dictization.model_dictize as model_dictize
...@@ -44,13 +46,38 @@ def munge_increment_name(data_dict): ...@@ -44,13 +46,38 @@ def munge_increment_name(data_dict):
data_dict['name'] = name data_dict['name'] = name
def check_password(password):
return (len(password) >= 8 and
any(c.islower() for c in password) and
any(c.isupper() for c in password) and
any((c.isalpha()==False) for c in password)) #Number or Special character
PASSWORD_ERROR_MESSAGE = {'security': ['Passwort muss mindestens acht Zeichen, einen Gross-, einen Kleinbuchstaben und entweder eine Zahl oder ein Sondernzeichen enthalten!']}
def odsh_user_create(context, data_dict): def odsh_user_create(context, data_dict):
model = context['model'] model = context['model']
password = data_dict.get('password')
if not password:
password = data_dict.get('password1')
if check_password(password):
user = user_create(context, data_dict) user = user_create(context, data_dict)
groups = toolkit.get_action('group_list')(data_dict={'all_fields': False}) groups = toolkit.get_action('group_list')(data_dict={'all_fields': False})
for group in groups: for group in groups:
group_member_create(context, {'id': group, 'username': user.get('name'), 'role': 'member'}) group_member_create(context, {'id': group, 'username': user.get('name'), 'role': 'member'})
return model_dictize.user_dictize(model.User.get(user.get('name')), context) return model_dictize.user_dictize(model.User.get(user.get('name')), context)
else:
raise logic.ValidationError(PASSWORD_ERROR_MESSAGE)
def tpsh_user_update(context, data_dict):
password = data_dict.get('password')
if not password:
password = data_dict.get('password1')
if password and not check_password(password):
raise logic.ValidationError(PASSWORD_ERROR_MESSAGE)
return user_update(context, data_dict)
@toolkit.side_effect_free @toolkit.side_effect_free
......
from ckan.lib.helpers import resource_display_name
from ckan.lib.helpers import is_url, url_for
def thumbnail_namespace(filename): def thumbnail_namespace(filename):
return "/" + filename return "/" + filename
def get_name_from_last_pdf_upload(package): def get_download_link_for_thumbnail(package):
resources = package.get('resources') resources = package.get('resources')
for resource in resources[::-1]: for resource in resources[::-1]:
url_type =resource.get('url_type') url_type =resource.get('url_type')
mimetype = resource.get('mimetype') mimetype = resource.get('mimetype')
if url_type == 'upload' and mimetype == 'application/pdf': if url_type == 'upload' and mimetype == 'application/pdf':
return resource_display_name(resource) package_id = resource.get('package_id')
resource_id = resource.get('id')
pre_resource_url = resource.get('url')
if is_url(pre_resource_url):
url_resource = pre_resource_url
else:
url_resource = url_for(controller='package',
action='resource_download',
id=package_id,
resource_id=resource_id,
filename=pre_resource_url,
qualified = True)
return url_resource
...@@ -22,8 +22,8 @@ class ThumbnailPlugin(plugins.SingletonPlugin): ...@@ -22,8 +22,8 @@ class ThumbnailPlugin(plugins.SingletonPlugin):
#IResourceController #IResourceController
def after_create(self, context, resource): def after_create(self, context, resource):
_, size, filename = thumbnail.create_thumbnail(context, resource) _, filename = thumbnail.create_thumbnail(context, resource)
thumbnail.write_thumbnail_into_package(context, resource, size, filename) thumbnail.write_thumbnail_into_package(context, resource, filename)
def after_update(self, context, resource): def after_update(self, context, resource):
thumbnail.check_and_create_thumbnail_after_update(context, resource) thumbnail.check_and_create_thumbnail_after_update(context, resource)
...@@ -54,5 +54,5 @@ class ThumbnailPlugin(plugins.SingletonPlugin): ...@@ -54,5 +54,5 @@ class ThumbnailPlugin(plugins.SingletonPlugin):
return { return {
'thumbnail_namespace':thumbnail_helpers.thumbnail_namespace, 'thumbnail_namespace':thumbnail_helpers.thumbnail_namespace,
'thumbnail_get_name_from_last_pdf_upload':thumbnail_helpers.get_name_from_last_pdf_upload 'thumbail_get_download_link':thumbnail_helpers.get_download_link_for_thumbnail
} }
...@@ -81,7 +81,7 @@ def create_thumbnail_from_file(file, old_filename): ...@@ -81,7 +81,7 @@ def create_thumbnail_from_file(file, old_filename):
def create_thumbnail_from_url(resource, old_filename): def create_thumbnail_from_url(resource, old_filename):
return False, None, None return False, None
''' '''
# Requests does not work on a server but on a local test enviroment. # Requests does not work on a server but on a local test enviroment.
# With the given configuration of a wsgi server and apache it did not work # With the given configuration of a wsgi server and apache it did not work
...@@ -114,15 +114,14 @@ def create_thumbnail_from_url(resource, old_filename): ...@@ -114,15 +114,14 @@ def create_thumbnail_from_url(resource, old_filename):
def create_thumbnail_from_memory(resource, old_filename): def create_thumbnail_from_memory(resource, old_filename):
path = get_filepath_to_resource(resource) path = get_filepath_to_resource(resource)
file_type = magic.from_file(path, mime = True) file_type = magic.from_file(path, mime = True)
resource_size = os.path.getsize(path)
if file_type == 'application/pdf': if file_type == 'application/pdf':
with open(path, 'rb') as file: with open(path, 'rb') as file:
new_filename = create_thumbnail_from_file(file, old_filename) new_filename = create_thumbnail_from_file(file, old_filename)
is_PDF = True is_PDF = True
return is_PDF, resource_size, new_filename return is_PDF, new_filename
else: else:
is_PDF = False is_PDF = False
return is_PDF, resource_size, None return is_PDF, None
def remove_thumbnail(context): def remove_thumbnail(context):
old_filename = get_filename_from_context(context) old_filename = get_filename_from_context(context)
...@@ -135,32 +134,33 @@ def create_thumbnail(context, resource): ...@@ -135,32 +134,33 @@ def create_thumbnail(context, resource):
old_filename = get_filename_from_context(context) old_filename = get_filename_from_context(context)
url_type = resource.get('url_type') url_type = resource.get('url_type')
if url_type == 'upload': if url_type == 'upload':
is_PDF, size, filename = create_thumbnail_from_memory(resource, old_filename) is_PDF, filename = create_thumbnail_from_memory(resource, old_filename)
else: else:
is_PDF, size, filename = create_thumbnail_from_url(resource, old_filename) is_PDF, filename = create_thumbnail_from_url(resource, old_filename)
return is_PDF, size, filename return is_PDF, filename
def check_and_create_thumbnail_after_update(context, resource): def check_and_create_thumbnail_after_update(context, resource):
package_id = resource.get('package_id') package_id = resource.get('package_id')
package = toolkit.get_action('package_show')(context, {'id': package_id}) package = toolkit.get_action('package_show')(context, {'id': package_id})
resources = package.get('resources') resources = package.get('resources')
if len(resources) > 0:
last_resource = resources.pop() last_resource = resources.pop()
last_resource_id = last_resource.get('id') last_resource_id = last_resource.get('id')
resource_id = resource.get('id') resource_id = resource.get('id')
if last_resource_id == resource_id and resource.get('url_type') != 'upload': if last_resource_id == resource_id and resource.get('url_type') != 'upload':
is_PDF, size, filename = create_thumbnail(context, resource) is_PDF, filename = create_thumbnail(context, resource)
if is_PDF: if is_PDF:
write_thumbnail_into_package(context, resource, size, filename) write_thumbnail_into_package(context, resource, filename)
def create_thumbnail_for_last_resource(context, resources): def create_thumbnail_for_last_resource(context, resources):
if len(resources) > 0: if len(resources) > 0:
last_resource = resources.pop() last_resource = resources.pop()
is_PDF, size, filename = create_thumbnail(context, last_resource) is_PDF, filename = create_thumbnail(context, last_resource)
if not is_PDF: if not is_PDF:
create_thumbnail_for_last_resource(context, resources) create_thumbnail_for_last_resource(context, resources)
else: else:
write_thumbnail_into_package(context, last_resource, size , filename) write_thumbnail_into_package(context, last_resource, filename)
else: else:
remove_thumbnail(context) remove_thumbnail(context)
package = context.get('package') package = context.get('package')
...@@ -169,20 +169,9 @@ def create_thumbnail_for_last_resource(context, resources): ...@@ -169,20 +169,9 @@ def create_thumbnail_for_last_resource(context, resources):
package.update({'thumbnail': None}) package.update({'thumbnail': None})
toolkit.get_action('package_update')(context, package) toolkit.get_action('package_update')(context, package)
def update_last_resource_if_value_empty(context, resource, key, value): def write_thumbnail_into_package(context, resource, filename):
package_id = resource.get('package_id') package_id = resource.get('package_id')
package = toolkit.get_action('package_show')(context, {'id': package_id}) package = toolkit.get_action('package_show')(context, {'id': package_id})
resources = package.get('resources')
last_resource = resources.pop()
if not last_resource.get(key):
last_resource.update({key: value})
resources.append(last_resource)
package.update({'resources': resources})
return package
def write_thumbnail_into_package(context, resource, size, filename):
package = update_last_resource_if_value_empty(context, resource, 'size', size)
if filename: if filename:
package.update({'thumbnail': filename}) package.update({'thumbnail': filename})
toolkit.get_action('package_update')(context, package) toolkit.get_action('package_update')(context, package)
\ No newline at end of file
...@@ -50,6 +50,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm ...@@ -50,6 +50,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm
def get_actions(self): def get_actions(self):
return {'package_create': action.odsh_package_create, return {'package_create': action.odsh_package_create,
'user_update':action.tpsh_user_update,
'user_create': action.odsh_user_create} 'user_create': action.odsh_user_create}
...@@ -200,7 +201,11 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm ...@@ -200,7 +201,11 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm
def after_create(self, context, resource): def after_create(self, context, resource):
if resource.get('package_id'): if resource.get('package_id'):
tools.save_hash_into_resource(context, resource) tools.add_attributes_resources(context, resource)
def after_update(self, context, resource):
if resource.get('package_id'):
tools.add_attributes_resources(context, resource)
@staticmethod @staticmethod
def _update_is_new_in_pkg_dict(pkg_dict): def _update_is_new_in_pkg_dict(pkg_dict):
...@@ -290,7 +295,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm ...@@ -290,7 +295,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm
m.connect('/user/logged_in', action='logged_in') m.connect('/user/logged_in', action='logged_in')
m.connect('/user/logged_out', action='logged_out') m.connect('/user/logged_out', action='logged_out')
m.connect('/user/logged_out_redirect', action='logged_out_page') m.connect('/user/logged_out_redirect', action='logged_out_page')
m.connect('user_datasets', '/user/{id:.*}', action='read', m.connect('user_datasets', '/user/{id:(?!(generate_key|activity)).*}', action='read',
ckan_icon='sitemap') ckan_icon='sitemap')
map.connect( map.connect(
...@@ -356,6 +361,8 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm ...@@ -356,6 +361,8 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm
'get_subject_for_selection': helpers_tpsh.get_subject_for_selection, 'get_subject_for_selection': helpers_tpsh.get_subject_for_selection,
'get_language_for_selection': helpers_tpsh.get_language_for_selection, 'get_language_for_selection': helpers_tpsh.get_language_for_selection,
'tpsh_get_resource_size': helpers_tpsh.get_resource_size, 'tpsh_get_resource_size': helpers_tpsh.get_resource_size,
'tpsh_get_address_org':helpers_tpsh.get_address_org,
'tpsh_get_body_mail':helpers_tpsh.get_body_mail,
} }
......
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>local_phone</title>
<desc>Created with Sketch.</desc>
<g id="Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Rounded" transform="translate(-341.000000, -3213.000000)">
<g id="Maps" transform="translate(100.000000, 3068.000000)">
<g id="-Round-/-Maps-/-local_phone" transform="translate(238.000000, 142.000000)">
<g>
<polygon id="Path" points="0 0 24 0 24 24 0 24"></polygon>
<path d="M19.23,15.26 L16.69,14.97 C16.08,14.9 15.48,15.11 15.05,15.54 L13.21,17.38 C10.38,15.94 8.06,13.63 6.62,10.79 L8.47,8.94 C8.9,8.51 9.11,7.91 9.04,7.3 L8.75,4.78 C8.63,3.77 7.78,3.01 6.76,3.01 L5.03,3.01 C3.9,3.01 2.96,3.95 3.03,5.08 C3.56,13.62 10.39,20.44 18.92,20.97 C20.05,21.04 20.99,20.1 20.99,18.97 L20.99,17.24 C21,16.23 20.24,15.38 19.23,15.26 Z" id="🔹-Icon-Color" fill="#003064"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg10"
xml:space="preserve"
width="793.70074"
height="1122.5197"
viewBox="0 0 793.70074 1122.5197"
sodipodi:docname="platzhalter.svg"
inkscape:version="0.92.4 (unknown)"><metadata
id="metadata16"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs14" /><sodipodi:namedview
pagecolor="#f1f1f1;"
bordercolor="#f1f1f1;"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1855"
inkscape:window-height="1056"
id="namedview12"
showgrid="false"
inkscape:zoom="0.81423964"
inkscape:cx="205.87465"
inkscape:cy="561.25983"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="g18" /><g
id="g18"
inkscape:groupmode="layer"
inkscape:label="plazthalter"
transform="matrix(1.3333333,0,0,-1.3333333,0,1122.5197)"><g
id="g20"><g
id="g22"
transform="matrix(1,0,0,-1,0,841.88977)"><path
d="M 2.145,1.891 H 597.856 V 844.032 H 2.145 Z"
style="fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#c8b7b7;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path24"
inkscape:connector-curvature="0" /></g></g></g></svg>
\ No newline at end of file
...@@ -79,6 +79,18 @@ h3{ ...@@ -79,6 +79,18 @@ h3{
font-size:20px; font-size:20px;
} }
.skip-link {
position: fixed;
top: -200px;
text-decoration: none;
padding: 10px;
display: inline-block;
}
.skip-link:focus {
top: 0;
}
.secondary h1.heading { .secondary h1.heading {
color:black; color:black;
font-weight: normal ; font-weight: normal ;
...@@ -106,12 +118,16 @@ h3{ ...@@ -106,12 +118,16 @@ h3{
} }
@media (max-width: 767px) { @media (max-width: 767px) {
.container, .container
.masthead .container
{ {
padding-right: 15px; padding-right: 15px;
padding-left: 15px; padding-left: 15px;
} }
.masthead .container
{
padding-right: 0;
padding-left: 0;
}
} }
.search-form, .odsh-dataset-heading { .search-form, .odsh-dataset-heading {
...@@ -123,6 +139,36 @@ h3{ ...@@ -123,6 +139,36 @@ h3{
margin-bottom: 0px; margin-bottom: 0px;
} }
@media (min-width: 1024px){
.search-form, .odsh-dataset-heading {
border-bottom: none;
margin-bottom: 0px;
margin-left: -15px;
margin-right: -15px;
padding-bottom: 0;
}
.search-form:after {
content: "";
display: block;
margin: 0 auto;
width: calc(100% - 30px);
padding-top: 25px;
border-bottom: 4px solid #dbdbdb;
order: 100;
}
.search-form h2 {
margin-left: 15px;
}
.form-select.control-group.control-order-by {
margin-left: 15px;
margin-right: 15px;
}
}
.organizaion-full-description{ .organizaion-full-description{
padding-bottom: 50px; padding-bottom: 50px;
...@@ -156,6 +202,7 @@ h3{ ...@@ -156,6 +202,7 @@ h3{
.odsh-dataset-heading .title .odsh-dataset-heading .title
{ {
margin-top: 0px; margin-top: 0px;
margin-bottom: 10px;
margin-right: 22px; margin-right: 22px;
font-size: 24px; font-size: 24px;
letter-spacing: 0.01em; letter-spacing: 0.01em;
...@@ -199,7 +246,11 @@ section#dataset-preview p { ...@@ -199,7 +246,11 @@ section#dataset-preview p {
display: flex; display: flex;
} }
.container-preview-large > img { .container-preview-large a {
margin-left: auto;
}
.container-preview-large img {
height: 100%; height: 100%;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
...@@ -270,6 +321,35 @@ section#dataset-collection .button-container img { ...@@ -270,6 +321,35 @@ section#dataset-collection .button-container img {
border-bottom: solid 3px #DBDBDB; border-bottom: solid 3px #DBDBDB;
} }
.information-organisation {
margin-top: 20px;
font-size: 12px;
text-align: left;
letter-spacing: 0.12px;
color: #000000;
}
.information-organisation p {
margin-bottom: 0;
}
.information-organisation a {
color: inherit;
}
.information-organisation .phone::before{
content: "";
display: inline-block;
background-image: url(/base/images/icon_phone.svg);
background-repeat: no-repeat;
background-size: .7rem .7rem;
background-position: 50% 50%;
width: 0.8rem;
height: 0.8rem;
vertical-align: middle;
}
.module-narrow .module-footer { .module-narrow .module-footer {
padding: 0; padding: 0;
border: none; border: none;
...@@ -464,7 +544,8 @@ input[type=radio], input[type=checkbox] { ...@@ -464,7 +544,8 @@ input[type=radio], input[type=checkbox] {
.category-header { .category-header {
display: inline-block; display: inline-block;
padding-right: 6px padding-right: 6px;
vertical-align: top;
} }
.category-icon-container { .category-icon-container {
...@@ -570,7 +651,8 @@ label.rangesearch.disabled { ...@@ -570,7 +651,8 @@ label.rangesearch.disabled {
.controls input.rangesearch{ .controls input.rangesearch{
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
padding: 12px 2px; height: 1.5rem;
padding: 2px;
font-style: normal; font-style: normal;
font-size: 12px; font-size: 12px;
line-height: 1.16666667em; line-height: 1.16666667em;
...@@ -628,6 +710,9 @@ label.rangesearch.disabled { ...@@ -628,6 +710,9 @@ label.rangesearch.disabled {
.odsh-dataset-item:hover { .odsh-dataset-item:hover {
background-color: rgb(246,247,249); background-color: rgb(246,247,249);
} }
.odsh-dataset-item:last-child {
border-bottom: none;
}
.preview-image-container { .preview-image-container {
display: flex; display: flex;
...@@ -642,7 +727,7 @@ label.rangesearch.disabled { ...@@ -642,7 +727,7 @@ label.rangesearch.disabled {
} }
} }
.preview-image-container > img { .preview-image-container img {
margin-top: auto; margin-top: auto;
height: auto; height: auto;
max-width: 102px; max-width: 102px;
...@@ -748,8 +833,6 @@ ul.dataset-resources { ...@@ -748,8 +833,6 @@ ul.dataset-resources {
} }
element.style {
}
.dataformat-label:hover { .dataformat-label:hover {
background-color: #d4004b!important; background-color: #d4004b!important;
} }
...@@ -760,10 +843,6 @@ element.style { ...@@ -760,10 +843,6 @@ element.style {
margin-bottom: 10px; margin-bottom: 10px;
} }
.popover-content{
}
.popover{ .popover{
width: unset; width: unset;
display:inline-table!important; display:inline-table!important;
...@@ -864,6 +943,11 @@ label:after { ...@@ -864,6 +943,11 @@ label:after {
font-style: normal; font-style: normal;
} }
input#field-username {
margin-bottom: 30px;
vertical-align: super;
}
.control-group.error input, .control-group.error input,
.control-group.error select, .control-group.error select,
.control-group.error .select2-choices, .control-group.error .select2-choices,
...@@ -1158,15 +1242,10 @@ label:after { ...@@ -1158,15 +1242,10 @@ label:after {
.footer a{ .footer a{
color:white; color:white;
} }
@media (max-width: 1023px){
.footer{
border-top:0px;
width: 100%;
}
body { body {
background-color: white; background-color: white;
} }
}
.footer .container{ .footer .container{
width: 100%; width: 100%;
max-width: 1000px; max-width: 1000px;
...@@ -1208,6 +1287,50 @@ body { ...@@ -1208,6 +1287,50 @@ body {
margin-top: 10px; margin-top: 10px;
} }
@media (max-width: 1023px){
.footer{
border-top-width: 30px;
width: 100%;
}
.footer-line{
border-top: 1px solid white;
}
}
@media (max-width: 767px){
.footer{
border-top-width: 20px;
}
.footer .container {
padding-bottom: 0;
}
.footer-line{
border-top: none;
margin-top: 0;
margin-bottom: 0;
}
.footer-content{
box-sizing: border-box;
padding-bottom: 15px;
background-image: none;
height: 139px;
display: flex;
flex-direction: column-reverse;
}
.footer-first-row{
padding-top: 0;
height: 0;
}
.footer-right{
display: flex;
justify-content: space-between;
padding-bottom: 15px;
}
.footer-icon a{
padding: 15px 0;
}
}
.toolbar .breadcrumb li:after { .toolbar .breadcrumb li:after {
background-image: url(/base/images/arrow-right.png); background-image: url(/base/images/arrow-right.png);
background-repeat: no-repeat; background-repeat: no-repeat;
...@@ -1355,14 +1478,10 @@ body { ...@@ -1355,14 +1478,10 @@ body {
text-align: center; text-align: center;
} }
element.style {
}
.dataformat-label:hover { .dataformat-label:hover {
background-color: #d4004b!important; background-color: #d4004b!important;
} }
.resource-title { .resource-title {
float: left; float: left;
margin-left: 5px; margin-left: 5px;
...@@ -1385,10 +1504,16 @@ element.style { ...@@ -1385,10 +1504,16 @@ element.style {
text-decoration: none text-decoration: none
} }
.resource-title p{ .resource-title p:first-of-type{
font-size: 12px; font-size: 12px;
letter-spacing: 0.12px; letter-spacing: 0.12px;
padding-top: 12px; padding-top: 12px;
margin-bottom: 0;
}
.resource-title p{
font-size: 12px;
letter-spacing: 0.12px;
padding-top: 0;
} }
.resource-title-container{ .resource-title-container{
...@@ -1852,6 +1977,10 @@ element.style { ...@@ -1852,6 +1977,10 @@ element.style {
} }
} }
#dataset-search-box-form{
margin-bottom: 0;
}
@media (max-width: 767px){ @media (max-width: 767px){
.site-title{ .site-title{
display: none; display: none;
...@@ -1865,12 +1994,14 @@ element.style { ...@@ -1865,12 +1994,14 @@ element.style {
#menu-button-and-title { #menu-button-and-title {
display: flex; display: flex;
align-items: center; align-items: center;
padding-left: 15px;
padding-right: 15px;
background-color: #f2f2f2;
} }
} }
#menu-button-and-title span { #menu-button-and-title span {
display: inline-block; display: inline-block;
color: #003064; color: #003064;
padding-left: 10px;
padding-right: 20px; padding-right: 20px;
} }
#menu-button-and-title h1 { #menu-button-and-title h1 {
...@@ -1885,11 +2016,23 @@ element.style { ...@@ -1885,11 +2016,23 @@ element.style {
margin-left: 0; margin-left: 0;
} }
.search-form .filter-list {
width: 100%
}
.filter-list .filtered.pill, .filter-list .filtered.pill,
.filter-list .filtered.pill .fa{ .filter-list .filtered.pill .fa{
background-color: #003064; background-color: #003064;
color:white; color:white;
} }
@media (min-width: 1024px){
.search-form .filter-list {
margin-left: 15px;
margin-right: 15px;
}
}
.filtered.pill.error{ .filtered.pill.error{
background-color: #d4004b; background-color: #d4004b;
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
padding-right: 0; padding-right: 0;
position: relative; position: relative;
top: 0; top: 0;
left: 18px;
padding: 1em 0; padding: 1em 0;
} }
......
...@@ -15,10 +15,10 @@ ...@@ -15,10 +15,10 @@
{% endif %} {% endif %}
<h3>Wie finde ich die gesuchten Inhalte im Landesportal?</h3> <h3>Wie finde ich die gesuchten Inhalte im Landesportal?</h3>
<p><a class="" href="http://www.schleswig-holstein.de/tpstart" title="Zur Startseite">Zur Startseite des Open-Data-Portals</a></p> <p><a class="" href="http://www.schleswig-holstein.de/tpstart" title="Zur Startseite">Zur Startseite des Transparenzportals</a></p>
<h3>Kontakt</h3> <h3>Kontakt</h3>
<p>Bei Fragen oder Problemen mit dem Open-Data-Portal schicken Sie bitte eine E-Mail an die Adresse opendata@lr.landsh.de oder verwenden das Kontaktformular:</p> <p>Bei Fragen oder Problemen mit dem Transparenzportal schicken Sie bitte eine E-Mail an die Adresse transparenz@lr.landsh.de oder verwenden das Kontaktformular:</p>
<p><a class="" href="https://www.schleswig-holstein.de/tpkontakt" title="Kontakt">Zum Kontaktformular</a></p> <p><a class="" href="https://www.schleswig-holstein.de/tpkontakt" title="Kontakt">Zum Kontaktformular</a></p>
</div> </div>
{% endif %} {% endif %}
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<div class='footer-line'></div> <div class='footer-line'></div>
<div class="footer-left"> <div class="footer-left">
<div class="footer-icon">&copy; {{g.site_title}}</div> <div class="footer-icon">&copy; {{g.site_title}}</div>
</div>
<div class="footer-right"> <div class="footer-right">
<div class='footer-icon'><a href='http://www.schleswig-holstein.de/tpkontakt'>Kontakt</a></div> <div class='footer-icon'><a href='http://www.schleswig-holstein.de/tpkontakt'>Kontakt</a></div>
<div class='footer-icon'><a href='http://www.schleswig-holstein.de/tpimpressum'>Impressum</a></div> <div class='footer-icon'><a href='http://www.schleswig-holstein.de/tpimpressum'>Impressum</a></div>
...@@ -15,5 +16,4 @@ ...@@ -15,5 +16,4 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</footer> </footer>
\ No newline at end of file
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
<ul class="nav nav-pills"> <ul class="nav nav-pills">
<li class="header-menu-mobile" data-module="tpsh_toggle_menu"> <li class="header-menu-mobile" data-module="tpsh_toggle_menu">
<a>Menü</a> <a>Menü</a>
<img src="/base/images/icon_close_white.svg"> <img src="/base/images/icon_close_white.svg" alt="Menü schließen" aria-label="Menü schließen">
</li> </li>
{% block header_site_navigation_tabs %} {% block header_site_navigation_tabs %}
{{ {{
...@@ -66,21 +66,21 @@ ...@@ -66,21 +66,21 @@
d="M42.5,44.5h-31v-6.4c0-4.7,3.9-8.6,8.6-8.6h13.9c4.7,0,8.6,3.9,8.6,8.6V44.5z" /> d="M42.5,44.5h-31v-6.4c0-4.7,3.9-8.6,8.6-8.6h13.9c4.7,0,8.6,3.9,8.6,8.6V44.5z" />
</svg> </svg>
{{name}}</a> {{name}}</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"> <ul class="dropdown-menu" role="menu">
<li> <li>
<svg class='user-icon-small' viewBox="0 0 54 54"> <svg class='user-icon-small' viewBox="0 0 54 54">
<circle cx="27" cy="17" r="7.5" /> <circle cx="27" cy="17" r="7.5" />
<path <path
d="M42.5,44.5h-31v-6.4c0-4.7,3.9-8.6,8.6-8.6h13.9c4.7,0,8.6,3.9,8.6,8.6V44.5z" /> d="M42.5,44.5h-31v-6.4c0-4.7,3.9-8.6,8.6-8.6h13.9c4.7,0,8.6,3.9,8.6,8.6V44.5z" />
</svg> </svg>
<a href="{{ h.url_for('/user/') }}" title="logout"> <a href="{{ h.url_for('/user/') }}" title="logout" role="menuitem">
<span class="text"> <span class="text">
Mein Profil einsehen Mein Profil einsehen
</span> </span>
</a> </a>
</li> </li>
<li> <li>
<a href="{{ h.url_for('/user/edit') }}" title="logout"> <a href="{{ h.url_for('/user/edit') }}" title="logout" role="menuitem">
<i class='fa fa-edit'></i> <i class='fa fa-edit'></i>
<span class="text"> <span class="text">
Mein Profil bearbeiten Mein Profil bearbeiten
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
</a> </a>
</li> </li>
<li> <li>
<a href="{{ h.url_for('/user/_logout') }}" title="logout"> <a href="{{ h.url_for('/user/_logout') }}" title="logout" role="menuitem">
<i class='fa fa-sign-out'></i> <i class='fa fa-sign-out'></i>
<span class="text">Logout</span> <span class="text">Logout</span>
</a> </a>
......
...@@ -95,6 +95,21 @@ is_required=false) %} ...@@ -95,6 +95,21 @@ is_required=false) %}
</div> </div>
{% endmacro %} {% endmacro %}
{% macro select(name, id='', label='', options='', selected='', error='', classes=[], attrs={'class': 'form-control'}, is_required=false) %}
{% set classes = (classes|list) %}
{% do classes.append('control-select') %}
{%- set extra_html = caller() if caller -%}
{% call input_block(id or name, label or name, error, classes, extra_html=extra_html, is_required=is_required) %}
<select id="{{ id or name }}" name="{{ name }}" {{ attributes(attrs) }}>
{% for option in options %}
<option value="{{ option.value }}"{% if option.value == selected %} selected{% endif %}>{{ option.text or option.value }}</option>
{% endfor %}
</select>
{% endcall %}
{% endmacro %}
{# {#
Creates all the markup required for an select element. Handles matching labels to Creates all the markup required for an select element. Handles matching labels to
inputs and error messages. inputs and error messages.
...@@ -119,7 +134,7 @@ Examples: ...@@ -119,7 +134,7 @@ Examples:
selected=2011, error=errors.year) }} selected=2011, error=errors.year) }}
#} #}
{% macro select(name, id='', label='', options='', selected='', error='', classes=[], attrs={}, {% macro tpsh_select(name, id='', label='', options='', selected='', error='', classes=[], attrs={},
is_required=false) %} is_required=false) %}
{% set classes = (classes|list) %} {% set classes = (classes|list) %}
{% do classes.append('control-select') %} {% do classes.append('control-select') %}
...@@ -346,6 +361,22 @@ is_required=is_required) %} ...@@ -346,6 +361,22 @@ is_required=is_required) %}
{% endcall %} {% endcall %}
{% endmacro %} {% endmacro %}
{% macro input_address(field, label, value='', index='', placeholder='', type='text', attrs={}) %}
{%- set _type = 'text' if type=='date' and not value else type -%}
{%- set onFocus = 'onfocus=(this.type=\'date\')' if type=='date' and not value else '' -%}
<div class="row-fluid">
<div class="span6">
<label class="address-label"> {{ label }} </label>
<input id="field-{{field}}-key" type="hidden" name="extras__{{index}}__key" value="{{field}}" />
<input id="field-{{field}}-value" type="{{_type}}" name="extras__{{index}}__value" value="{{value | empty_and_escape }}" placeholder="{{ placeholder }}" {{ onFocus }} {{ attributes(attrs) }}/>
</div>
</div>
{% endmacro %}
{# {#
A generic input_block for providing the default markup for CKAN form elements. A generic input_block for providing the default markup for CKAN form elements.
It is expected to be called using a {% call %} block, the contents of which It is expected to be called using a {% call %} block, the contents of which
......
...@@ -26,31 +26,22 @@ ...@@ -26,31 +26,22 @@
{% endblock %} {% endblock %}
{% block custom_fields %}
{% for extra in data.extras %}
{% set prefix = 'extras__%d__' % loop.index0 %}
{{ form.custom( {% set extras = h.tpsh_get_address_org(data) %}
names=(prefix ~ 'key', prefix ~ 'value', prefix ~ 'deleted'),
id='field-extras-%d' % loop.index, {{ form.input_address('person','Ansprechpartner', value= extras.person , index=0, placeholder='', type='text', attrs={}) }}
label=_('Custom Field'),
values=(extra.key, extra.value, extra.deleted), {{ form.input_address('street','Straße', value= extras.street, index=1, placeholder='', type='text', attrs={}) }}
error=errors[prefix ~ 'key'] or errors[prefix ~ 'value']
) }} {{ form.input_address('location','Stadt', value=extras.location, index=2, placeholder='', type='text', attrs={}) }}
{% endfor %}
{{ form.input_address('telephone','Tel.-Nr.:', value=extras.telephone, index=3, placeholder='', type='text', attrs={}) }}
{# Add a max if 3 empty columns #}
{% for extra in range(data.extras|count, 3) %} {{ form.input_address('mail','e-mail', value=extras.mail, index=4, placeholder='', type='text', attrs={}) }}
{% set index = (loop.index0 + data.extras|count) %}
{% set prefix = 'extras__%d__' % index %} {{ form.input_address('web','Website', value=extras.web, index=5, placeholder='', type='text', attrs={}) }}
{{ form.custom(
names=(prefix ~ 'key', prefix ~ 'value', prefix ~ 'deleted'),
id='field-extras-%d' % index,
label=_('Custom Field'),
values=(extra.key, extra.value, extra.deleted),
error=errors[prefix ~ 'key'] or errors[prefix ~ 'value']
) }}
{% endfor %}
{% endblock %}
{{ form.required_message() }} {{ form.required_message() }}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment