Compare commits

..

61 Commits

Author SHA1 Message Date
Frédéric Péters 4547aa44e3 remove breadcrumb display artefact on chromium 2018-11-22 15:45:46 +01:00
Frédéric Péters d660b76935 adjust logout link on mobile 2018-11-22 14:40:57 +01:00
Frédéric Péters 5c8b849f2f add custom style for "only display fields of this page" 2018-11-22 14:23:33 +01:00
Frédéric Péters 6b56793980 size logout link to be an easier target 2018-11-22 14:17:14 +01:00
Frédéric Péters b76001d6ee improve blue contrast for accessibility (#28252) 2018-11-22 13:51:01 +01:00
Frédéric Péters bfba9b1bcc add hack for wcs sticky sidebar width 2018-11-21 17:04:44 +01:00
Frédéric Péters 3b2bc553ec style search results that have no links 2018-11-21 16:21:30 +01:00
Frédéric Péters 9711e27852 use a variable for base text color 2018-11-21 16:21:30 +01:00
Frédéric Péters 3e759f2c8c remove usage of css variables, not ready enough 2018-11-21 16:21:30 +01:00
Frédéric Péters 5fd75f8d29 calmer colour for wcs badges 2018-11-21 16:21:30 +01:00
Frédéric Péters c8344b3a81 remove sidemenu from base template
(to be added to publik themes)
2018-11-21 16:21:30 +01:00
Frédéric Péters f76491ce6e remove obsolete breadcrumb styles 2018-11-21 16:21:30 +01:00
Frédéric Péters 478c78afe5 fix slight overflowing of fieldset.foldable 2018-11-21 16:21:30 +01:00
Frédéric Péters 54ed878865 more wcs adjustments 2018-11-21 16:21:30 +01:00
Frédéric Péters b037221435 style notification & workflow messages 2018-11-21 16:21:30 +01:00
Frédéric Péters 6222816ae6 adapt header and sidemenu to mobiles 2018-11-21 16:21:30 +01:00
Frédéric Péters c9dd47af60 reduce sidebar toggle width 2018-11-21 16:21:30 +01:00
Frédéric Péters 9e1d35f4c2 declare all opensans font variants 2018-11-21 16:21:30 +01:00
Frédéric Péters 8f5d3e1b2f cleanup 2018-11-21 16:21:30 +01:00
Frédéric Péters 25ea50f97d style ckeditor 2018-11-21 16:21:30 +01:00
Frédéric Péters 55ed54ea57 add icons for actions 2018-11-21 16:21:30 +01:00
Frédéric Péters 172f1449e1 general: add new application icons (#28031) 2018-11-21 16:21:28 +01:00
Frédéric Péters f451d65819 include "work area" picture (#28030) 2018-11-21 16:20:41 +01:00
Frédéric Péters 4a8d87e658 remove header background image scrolling effect 2018-11-21 16:20:41 +01:00
Frédéric Péters 4ddda31322 split app & hacks in specific files 2018-11-21 16:20:41 +01:00
Frédéric Péters 9f293656e7 add basic styles for page content cells 2018-11-21 16:20:41 +01:00
Frédéric Péters 8035dbb55f reduce (invisible) width of header 2018-11-21 16:20:41 +01:00
Frédéric Péters bb0c7e5487 style pagination 2018-11-21 16:20:41 +01:00
Frédéric Péters 401d2a674a darken main titles 2018-11-21 16:20:41 +01:00
Frédéric Péters 0e3b6aaafa use primary color for app tile links 2018-11-21 16:20:41 +01:00
Frédéric Péters cd4cf5b59d don't use orange for link bottom border 2018-11-21 16:20:41 +01:00
Frédéric Péters e779fef528 adjust sidebar width & margin 2018-11-21 16:20:41 +01:00
Frédéric Péters 5cad10dc82 give solid white background to sidebar 2018-11-21 16:20:41 +01:00
Frédéric Péters c1f6b6f788 don't add extra padding to #content 2018-11-21 16:20:41 +01:00
Frédéric Péters ef5a2c5700 experiments in notification colours 2018-11-21 16:20:41 +01:00
Frédéric Péters a786dc1686 steps in backoffice submission 2018-11-21 16:20:41 +01:00
Frédéric Péters ff7fd9a25b error message 2018-11-21 16:20:41 +01:00
Frédéric Péters 54b433e525 big msg info 2018-11-21 16:20:41 +01:00
Frédéric Péters fde453cbfd style tables 2018-11-21 16:20:41 +01:00
Frédéric Péters ccfc708a3d style buttons 2018-11-21 16:20:41 +01:00
Frédéric Péters 3da0b99917 restyle bo blocks 2018-11-21 16:20:41 +01:00
Frédéric Péters 5c867de9ee light background gradient 2018-11-21 16:20:41 +01:00
Frédéric Péters 82204b268c add various (temporary) hacks for applications 2018-11-21 16:20:41 +01:00
Frédéric Péters 86fc6c6ca1 style appbar links and kebab menu 2018-11-21 16:20:41 +01:00
Frédéric Péters 674050dbb6 don't add a solid background to main content 2018-11-21 16:20:41 +01:00
Frédéric Péters 0df1605123 add more space around sidemenu icons 2018-11-21 16:20:41 +01:00
Frédéric Péters de305d3623 fix calculations of sidepage variable widths 2018-11-21 16:20:41 +01:00
Frédéric Péters 4e78ef6324 add arrow to selected item in sidemenu 2018-11-21 16:20:41 +01:00
Frédéric Péters 01abe8db3e add right border to side menu 2018-11-21 16:20:41 +01:00
Frédéric Péters 30c565bb49 make sure content is cleared 2018-11-21 16:20:41 +01:00
Frédéric Péters 0593f5bab5 adjust more spacings 2018-11-21 16:20:41 +01:00
Frédéric Péters 4beff5c3e3 sidepage adjustments 2018-11-21 16:20:41 +01:00
Frédéric Péters 09972fbaa5 sidebar 2018-11-21 16:20:41 +01:00
Frédéric Péters a5ef91c8f4 style: forms 2018-11-21 16:20:41 +01:00
Frédéric Péters 110363f6ed style: dialogs 2018-11-21 16:20:41 +01:00
Frédéric Péters 302da15b9b sidemenu expander 2018-11-21 16:20:41 +01:00
Frédéric Péters b7ecd3eaad include platform name in header 2018-11-21 16:20:41 +01:00
Frédéric Péters 319253eda8 bo 2018 2018-11-21 16:20:40 +01:00
Frédéric Péters 654a8ffe16 bo next 2018-11-21 16:19:39 +01:00
Frédéric Péters f0184da515 restyle backoffice 2018-11-21 16:19:39 +01:00
Frédéric Péters 6edb61b464 re style, 1st draft 2018-11-21 16:19:39 +01:00
70 changed files with 768 additions and 3351 deletions

View File

@ -1,131 +0,0 @@
env:
browser: true
es2017: true
extends: eslint:recommended
parserOptions:
sourceType: module
ignorePatterns:
- "gadjo/static/js/gadjo.js"
rules:
# Follow Standard JS guidelines : https://standardjs.com/rules.html, except rules
# annotated with a 'custom' comment
# Linting
array-callback-return: error
constructor-super: error
eqeqeq: [error, always, {null: ignore}]
handle-callback-err: error
no-array-constructor: error
no-caller: error
no-class-assign: error
no-cond-assign: error
no-const-assign: error
no-control-regex: error
no-debugger: error
no-delete-var: error
no-dupe-args: error
no-dupe-class-members: error
no-dupe-keys: error
no-duplicate-case: error
no-duplicate-imports: error
no-empty-character-class: error
no-empty-pattern: error
no-eval: error
no-ex-assign: error
no-extend-native: error
no-extra-boolean-cast: error
no-fallthrough: error
no-func-assign: error
no-global-assign: error
no-implied-eval: error
no-inner-declarations: error
no-invalid-regexp: error
no-iterator: error
no-labels: error
no-new-func: error
no-new-object: error
no-new-require: error
no-new-symbol: error
no-new-wrappers: error
no-new: error
no-obj-calls: error
no-octal-escape: error
no-octal: error
no-proto: error
no-redeclare: error
no-regex-spaces: error
no-return-assign: error
no-self-assign: error
no-self-compare: error
no-sequences: error
no-shadow-restricted-names: error
no-sparse-arrays: error
no-template-curly-in-string: error
no-this-before-super: error
no-throw-literal: error
no-undef: error
no-unexpected-multiline: error
no-unmodified-loop-condition: error
no-unneeded-ternary: error
no-unreachable: error
no-unsafe-finally: error
no-unsafe-negation: error
no-unused-vars: error
no-use-before-define: [error, {functions: false, variables: false, classes: false}]
no-useless-call: error
no-useless-computed-key: error
no-useless-constructor: error
no-useless-escape: error
no-var: error
no-with: error
use-isnan: error
valid-typeof: error
# Style / Formatting
accessor-pairs: error
block-spacing: error
brace-style: [error, 1tbs, {allowSingleLine: true}]
camelcase: error
comma-dangle: [error, always-multiline] # custom : Adding a dangling comma make patches shorter
comma-spacing: error
comma-style: error
curly: [error, multi-line]
dot-location: [error, property]
eol-last: [error, always]
func-call-spacing: error
indent: [error, 2]
key-spacing: error
keyword-spacing: error
max-len: [error, {code: 110}] # custom: configured like this on python projects
new-cap: [error, { newIsCap: true, capIsNew: false}]
new-parens: error
no-extra-parens: [error, functions]
no-floating-decimal: error
no-irregular-whitespace: error
no-lone-blocks: error
no-mixed-spaces-and-tabs: error
no-multi-spaces: error
no-multi-str: error
no-multiple-empty-lines: error
no-tabs: error
no-trailing-spaces: error
no-undef-init: error
no-useless-rename: error
no-whitespace-before-property: error
object-property-newline: [error, { allowMultiplePropertiesPerLine: true }]
one-var: [error, never]
operator-linebreak: [error, before]
padded-blocks: [error, never]
quotes: [error, single]
rest-spread-spacing: error
semi-spacing: error
semi: [error, never]
space-before-function-paren: error
space-in-parens: error
space-infix-ops: error
space-unary-ops: error
spaced-comment: error
template-curly-spacing: error
wrap-iife: [error, any]
yield-star-spacing: [error, {after: true, before: true}]

View File

@ -1,4 +0,0 @@
# misc: apply djhtml (#69422)
318d6fb378205d0529a2bd152212c050c8fccfa6
# misc: apply double-quote-string-fixer (#79788)
346e0a4d72c526aa4ed7e9b9015916aa59b6debc

8
.gitignore vendored
View File

@ -1,13 +1,5 @@
*.pyc
*.swp
.eggs
/dist
/gadjo.egg-info
/gadjo/locale/fr/LC_MESSAGES/django.mo
/gadjo/static/css/gadjo.css
/gadjo/static/css/gadjo.multiselectwidget.css
/gadjo/static/css/gadjo.snapshotdiff.css
/gadjo/static/css/icons
node_modules
MANIFEST
build

View File

@ -1,38 +0,0 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: double-quote-string-fixer
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
args: ['--target-version', 'py37', '--skip-string-normalization', '--line-length', '110']
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort
args: ['--profile', 'black', '--line-length', '110']
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
hooks:
- id: pyupgrade
args: ['--keep-percent-format', '--py39-plus']
- repo: https://github.com/rtts/djhtml
rev: '3.0.6'
hooks:
- id: djhtml
args: ['--tabwidth', '2']
- repo: https://git.entrouvert.org/pre-commit-debian.git
rev: v0.3
hooks:
- id: pre-commit-debian
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.36.0
hooks:
- id: eslint
files: \.m?js$
types: [file]
args: [--fix]

54
Jenkinsfile vendored
View File

@ -1,54 +0,0 @@
@Library('eo-jenkins-lib@main') import eo.Utils
pipeline {
agent any
options { disableConcurrentBuilds() }
stages {
stage('Unit Tests') {
steps {
sh 'tox -rv'
}
post {
always {
script {
utils = new Utils()
utils.publish_coverage('coverage.xml')
utils.publish_coverage_native('index.html')
utils.publish_pylint('pylint.out')
}
mergeJunitResults()
}
}
}
stage('Packaging') {
steps {
script {
env.SHORT_JOB_NAME=sh(
returnStdout: true,
// given JOB_NAME=gitea/project/PR-46, returns project
// given JOB_NAME=project/main, returns project
script: '''
echo "${JOB_NAME}" | sed "s/gitea\\///" | awk -F/ '{print $1}'
'''
).trim()
if (env.GIT_BRANCH == 'main' || env.GIT_BRANCH == 'origin/main') {
sh "sudo -H -u eobuilder /usr/local/bin/eobuilder -d bullseye,bookworm ${SHORT_JOB_NAME}"
} else if (env.GIT_BRANCH.startsWith('hotfix/')) {
sh "sudo -H -u eobuilder /usr/local/bin/eobuilder -d bullseye,bookworm --branch ${env.GIT_BRANCH} --hotfix ${SHORT_JOB_NAME}"
}
}
}
}
}
post {
always {
script {
utils = new Utils()
utils.mail_notify(currentBuild, env, 'ci+jenkins-gadjo@entrouvert.org')
}
}
success {
cleanWs()
}
}
}

View File

@ -4,6 +4,5 @@ include MANIFEST.in
include AUTHORS
include COPYING
include VERSION
include inkscape_wrapper.py
recursive-include gadjo/static *.scss *.css *.map *.png *.gif *.eot *.woff *.ttf *.svg *.jpg *.jpeg *.js README.md LICENSE release.sh
recursive-include icons *.svg

View File

@ -21,6 +21,11 @@ You should add gadjo.finders.XStaticFinder to STATICFILES_FINDERS,
STATICFILES_FINDERS = global_settings.STATICFILES_FINDERS + \
('gadjo.finders.XStaticFinder',)
There is a CDNS settings, that can contain a list of (cdn name, protocol)
tuples; for example:
CDNS = [('google', 'https')]
Additional static files
------------------------

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
7

22
debian/control vendored
View File

@ -2,23 +2,11 @@ Source: gadjo
Maintainer: Frederic Peters <fpeters@entrouvert.com>
Section: python
Priority: optional
Build-Depends: debhelper-compat (= 12),
dh-python,
dpkg-dev,
inkscape,
libjpeg-dev,
python3-all,
python3-django,
python3-pil,
python3-setuptools,
sassc,
zlib1g-dev,
Build-Depends: python-setuptools (>= 33), python-pkg-resources (>= 33), dh-python, dpkg-dev, python-all (>= 2.6.6-3), python2.7-dev, python-all-dev, debhelper (>= 7), python-django, inkscape, python-imaging, libjpeg-dev, zlib1g-dev, ruby-sass (>= 3.4)
Standards-Version: 3.9.1
Package: python3-gadjo
Package: python-gadjo
Architecture: all
Depends: libjs-jquery,
python3-django,
${misc:Depends},
${python3:Depends},
Description: Base templates for management interfaces (Python 3)
Depends: ${misc:Depends}, ${python:Depends}, python-django, libjs-jquery
Description: Base templates for management interfaces

View File

@ -1,4 +0,0 @@
xstatic_font_awesome python3-xstatic-font-awesome
xstatic_opensans python3-xstatic-opensans
xstatic_jquery python3-xstatic-jquery
xstatic_jquery_ui python3-xstatic-jquery-ui

View File

@ -1,5 +1 @@
xstatic python-xstatic
xstatic_font_awesome python-xstatic-font-awesome
xstatic_opensans python-xstatic-opensans
xstatic_jquery python-xstatic-jquery
xstatic_jquery_ui python-xstatic-jquery-ui

7
debian/rules vendored
View File

@ -1,7 +1,6 @@
#!/usr/bin/make -f
export PYBUILD_NAME=gadjo
export PYBUILD_DISABLE=test
%:
dh $@ --with python3 --buildsystem=pybuild
dh $@ --with python2

View File

@ -1 +0,0 @@
3.0 (quilt)

View File

@ -1 +1 @@
__version__ = '0.4.3'
__version__ = "0.4.3"

View File

@ -11,7 +11,6 @@ from django.contrib.staticfiles import utils
from django.contrib.staticfiles.finders import BaseFinder
from django.core.exceptions import ImproperlyConfigured
from django.core.files.storage import FileSystemStorage
try:
from importlib import import_module
except ImportError:
@ -23,7 +22,6 @@ class XStaticStorage(FileSystemStorage):
A file system storage backend that takes an xstatic package module and works
for the data contained in it.
"""
prefix = 'xstatic'
def __init__(self, package, *args, **kwargs):
@ -35,7 +33,7 @@ class XStaticStorage(FileSystemStorage):
except ImportError:
raise ImproperlyConfigured('Cannot import module "%s"' % package)
location = package.BASE_DIR
super().__init__(location, *args, **kwargs)
super(XStaticStorage, self).__init__(location, *args, **kwargs)
class XStaticFinder(BaseFinder):
@ -60,14 +58,14 @@ class XStaticFinder(BaseFinder):
self.storages[app] = app_storage
if app not in self.apps:
self.apps.append(app)
super().__init__(*args, **kwargs)
super(XStaticFinder, self).__init__(*args, **kwargs)
def find(self, path, all=False):
"""Look for files in the registered xstatic.* packages"""
if path.startswith(self.storage_class.prefix + '/'):
path = path[len(self.storage_class.prefix) + 1 :]
path = path[len(self.storage_class.prefix)+1:]
matches = []
for storage in self.storages.values():
for app, storage in self.storages.items():
if storage.exists(path):
matched_path = storage.path(path)
if matched_path:
@ -76,8 +74,8 @@ class XStaticFinder(BaseFinder):
matches.append(matched_path)
return matches
def list(self, ignore_patterns=None):
def list(self, ignore_patterns=[]):
"""List all files in registered xstatic.* packages"""
for storage in self.storages.values():
for path in utils.get_files(storage, ignore_patterns or []):
for app, storage in self.storages.items():
for path in utils.get_files(storage, ignore_patterns):
yield path, storage

View File

@ -1,41 +0,0 @@
from django import forms
class MultiSelectWidget(forms.MultiWidget):
template_name = 'gadjo/widgets/multiselectwidget.html'
class Media:
js = ('js/gadjo.multiselectwidget.js',)
css = {'all': ('css/gadjo.multiselectwidget.css',)}
def __init__(self, attrs=None):
self.attrs = attrs
widgets = [forms.Select(attrs=attrs)]
super().__init__(widgets, attrs)
def get_context(self, name, value, attrs):
if not isinstance(value, list):
value = [value]
self.widgets = []
for _ in range(max(len(value), 1)):
self.widgets.append(forms.Select(attrs=self.attrs, choices=self.choices))
# all subwidgets must have the same name
self.widgets_names = [''] * len(self.widgets)
return super().get_context(name, value, attrs)
def decompress(self, value):
return value or []
def value_from_datadict(self, data, files, name):
values = [x for x in data.getlist(name) if x]
# remove duplicates while keeping order
return list(dict.fromkeys(values))
def id_for_label(self, id_):
return id_
def value_omitted_from_data(self, *args, **kwargs):
return super(forms.MultiWidget, self).value_omitted_from_data(*args, **kwargs)

View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gadjo 0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-10-06 15:43+0200\n"
"PO-Revision-Date: 2023-10-06 15:43+0200\n"
"POT-Creation-Date: 2016-11-13 21:40+0100\n"
"PO-Revision-Date: 2016-11-13 21:45+0100\n"
"Last-Translator: Frederic Peters <fpeters@entrouvert.com>\n"
"Language: French\n"
"MIME-Version: 1.0\n"
@ -16,60 +16,35 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: templates/gadjo/form.html:4
msgid "There were errors processing your form."
msgstr "Il y a eu un problème à la validation du formulaire."
#: templates/gadjo/form.html:12
#: templates/gadjo/form.html:9
#, python-format
msgid "(Hidden field %(name)s) %(error)s"
msgstr "(champ caché %(name)s) %(error)s"
#: templates/gadjo/password-widget.html:8
msgid "Display password"
msgstr "Afficher le mot de passe"
#: templates/gadjo/password-widget.html:9
msgid "Display"
msgstr "Afficher"
#: templates/gadjo/root.html:27
msgid "quick access"
msgstr "accès rapides"
#: templates/gadjo/root.html:29
msgid "Go to content"
msgstr "Aller au contenu"
#: templates/gadjo/root.html:44
#: templates/gadjo/root.html:32
msgid "Logout"
msgstr "Déconnexion"
#: templates/gadjo/root.html:65
#: templates/gadjo/root.html:48
msgid ""
"\n"
" <p><strong>Do you know your web browser is obsolete?</strong> We "
"recommend\n"
" you to <a href=\"http://windows.microsoft.com/en-us/internet-explorer/"
"download-ie\">update\n"
" your web browser</a> or to <a href=\"http://browsehappy.com/\">use\n"
" different web browsers</a> as some features may not work.\n"
" "
msgstr ""
"\n"
" <p><strong>Savez-vous que votre navigateur est obsolète ?</strong> "
" Nous vous recommandons de "
" <a href=\"http://windows.microsoft.com/en-us/internet-explorer/"
"download-ie\">mettre à jour votre navigateur</a> ou d'"
"<a href=\"http://browsehappy.com/\">utiliser un navigateur"
" différent</a>.\n"
" "
#: templates/gadjo/root.html:63
msgid "Homepage"
msgstr "Accueil"
#: templates/gadjo/widget.html:12
msgid "This field is required."
msgstr "Ce champ est obligatoire."
#: templates/gadjo/widget.html:14
msgid "(optional)"
msgstr "(optionnel)"
#: templates/gadjo/widgets/multiselectwidget.html:3
#: templates/gadjo/widgets/multiselectwidget.html:7
msgid "Value"
msgstr "Valeur"
#: templates/gadjo/widgets/multiselectwidget.html:10
msgid "Remove"
msgstr "Supprimer"
#: templates/gadjo/widgets/multiselectwidget.html:10
msgid "Remove value"
msgstr "Supprimer la valeur"
#: templates/gadjo/widgets/multiselectwidget.html:16
msgid "Add"
msgstr "Ajouter"

View File

@ -1,45 +0,0 @@
// colors chart
$blue: #386ede;
$blue-dusty: #215D9C;
$blue-dark: #003388;
$cyan: #00d6eb;
$orange: hsl(30, 100%, 46%);
$red: hsl(355, 80%, 45%);
$brown: hsl(10, 70%, 30%);
$yellow-dark: hsl(60, 98%, 30%);
$green: hsl(120, 57%, 35%);
$green-dark: hsl(150, 57%, 25%);
$pink: hsl(320, 70%, 60%);
html {
--blue: #{$blue};
--blue-dusty: #{$blue-dusty};
--blue-dark: #{$blue-dark};
--cyan: #{$cyan};
--orange: #{$orange};
--red: #{$red};
--brown: #{$brown};
--yellow-dark: #{$yellow-dark};
--green: #{$green};
--green-dark: #{$green-dark};
--pink: #{$pink};
}
// colors attribution
$font-color: #3c3c33;
$primary-color: $blue;
$secondary-color: $cyan;
$link-color: $primary-color;
html {
--primary-color: #{$primary-color};
--secondary-color: #{$secondary-color};
--font-color: #{$font-color};
--font-color-light: #666;
--link-color: #{$primary-color};
--link-hover-color: #{$blue-dark};
--link-disabled-color: #aaa;
--background: #ecf0f3;
}

View File

@ -1,20 +1,7 @@
@charset "UTF-8";
$widget-background: white;
$widget-focus-background: white;
$widget-border: 1px solid #AAA;
$widget-focus-border: $widget-border;
$widget-border-radius: 0;
$widget-color: black;
$widget-focus-color: $widget-color;
$widget-focus-outline: 1px solid $primary-color;
$widget-focus-outline-offset: 0;
$button-delete-color: $red;
$button-focus-outline: $widget-focus-outline !default;
$button-focus-outline-offset: $widget-focus-outline-offset !default;
$data_uri_arrow-down: "arrow-down.svg";
$button-color: $primary-color;
$button-cancel-color: grayscale($button-color);
$button-delete-color: #CD2026;
$button-submit-color: #215D9C;
input, select, button, textarea {
font-size: 100%;
@ -27,7 +14,7 @@ label {
}
form div.widget {
margin-bottom: 1.5em;
margin-bottom: 2ex;
}
div.errornotice p {
@ -46,24 +33,18 @@ div.error {
background: transparent;
padding-left: 0px;
margin-left: 2px;
}
&::before {
content: "\f071"; /* fa-exclamation-triangle */
font-family: FontAwesome;
padding-right: 1ex;
}
p {
display: inline-block;
margin: 0;
}
div.error::before {
content: "\f071"; /* fa-exclamation-triangle */
font-family: FontAwesome;
padding-right: 1ex;
}
span.required {
margin-left: 0.3em;
margin-left: 0.7ex;
position: relative;
top: -0.1em;
cursor: help;
top: -0.2ex;
}
div.widget div.title {
@ -83,94 +64,71 @@ div.buttons div {
}
a.button {
padding-bottom: calc(1ex + 1px);
line-height: 2.5em;
}
%button {
--color: var(--primary-color);
--outline-color: var(--primary-color);
--hover-color: white;
--hover-background: var(--color);
display: inline-block;
padding: 5px 15px;
cursor: pointer;
border: 0px solid #aaa;
@include vendor-prefix('transition', 'all 200ms ease');
vertical-align: baseline;
border-radius: 3px;
font-weight: bold;
background: white;
text-align: center;
border: 1px solid var(--color);
color: var(--color);
transition: border-color 0.2s ease, box-shadow 0.2s linear;
&[aria-pressed=true], &:hover {
border-color: hsla(0, 0%, 0%, 0.6);
background: var(--hover-background);
color: var(--hover-color);
border: 1px solid $button-color;
color: $button-color;
&:hover {
background: $button-color;
color: white;
border-color: darken($button-color, 20%);
}
&.disabled, &:disabled {
box-shadow: none;
cursor: not-allowed;
background: #f3f3f3;
color: #888;
border-color: #888;
pointer-events: none;
}
&:active { border-color: hsla(0, 0%, 0%, 0.3); }
&:active { border-color: darken($button-color, 10%); }
&:focus {
@if $button-focus-outline == none {
outline: 1px dotted $button-background;
} @else {
outline: 1px solid var(--outline-color);
outline-offset: $button-focus-outline-offset;
}
border-color: darken($button-color, 20%);
}
@include vendor-prefix('transition', 'border-color 0.2s ease, box-shadow 0.2s linear');
}
a.button, a.pk-button, a[class*=pk-button-], a.pk-big-button, a[class*="pk-big-button-"], button, input[type=submit], div.buttons input, div.buttons a.cancel {
a.button, button, input[type=submit], div.buttons input {
@extend %button;
}
a.pk-big-button, a[class*="pk-big-button-"] {
padding: 2rem 4rem;
}
input[type=submit] {
height: 2.3rem;
}
%cancel-button,
a.cancel-button, button.cancel-button, a.pk-button-cancel, a.pk-big-button-cancel, div.buttons .cancel-button input, div.buttons a.cancel, div.buttons .cancel-button button {
--color: #727272;
--hover-color: var(--color);
--hover-background: #eee;
}
div.buttons {
display: flex;
flex-wrap: wrap;
// always force cancel button to be last
a.cancel {
order: 100;
margin-left: 1em;
a.cancel-button, button.cancel-button, div.buttons .cancel-button input, div.buttons .cancel-button button {
color: $button-cancel-color;
border-color: $button-cancel-color;
&:hover {
background: white;
border-color: darken($button-cancel-color, 20%);
}
// make sure adjacent buttons have a margin
button + button,
button + a {
margin-left: 1em;
&:active { border-color: darken($button-cancel-color, 10%); }
}
a.delete-button, button.delete-button, div.buttons .delete-button input, div.buttons .delete-button button {
color: $button-delete-color;
border-color: $button-delete-color;
&:hover {
background: $button-delete-color;
color: white;
border-color: darken($button-delete-color, 20%);
}
&:active { border-color: darken($button-delete-color, 10%); }
}
%delete-button,
a.delete-button, button.delete-button, a.pk-button-delete, a.pk-big-button-delete, div.buttons .delete-button input, div.buttons .delete-button button {
--color: #{$button-delete-color};
--outline-color: #{darken($button-delete-color, 10%)};
}
%submit-button,
a.submit-button, button.submit-button, a.pk-button-submit, a.pk-big-button-submit, div.buttons .submit-button input, div.buttons .submit-button button {
--color: var(--blue-dusty);
a.submit-button, button.submit-button, div.buttons .submit-button input, div.buttons .submit-button button {
color: $button-submit-color;
border-color: $button-submit-color;
&:hover {
color: white;
background: $button-submit-color;
border-color: darken($button-submit-color, 20%);
}
&:active { border-color: darken($button-submit-color, 10%); }
}
form.disabled-during-submit {
@ -197,24 +155,17 @@ input[type=submit]:disabled {
}
input, input[type="text"], input[type="url"], input[type="email"], input[type="password"], input[type="url"], input[type="tel"], input[type="number"], input[type="search"], input[type="file"], input[type="date"], input[type="datetime-local"], input[type="month"], input[type="time"], input[type="week"], textarea, select {
border: $widget-border;
border-radius: $widget-border-radius;
border: 1px solid #AAA;
border-radius: 0px;
box-sizing: border-box;
margin: 0.2em 0px;
outline: medium none;
padding: 0.7ex 0.7em;
max-width: 100%;
transition: background-size 0.2s ease;
background: $widget-background;
color: $widget-color;
&:focus:not([readonly]) {
background-color: $widget-focus-background;
border: $widget-focus-border;
color: $widget-focus-color;
}
@include vendor-prefix('transition', 'background-size 0.2s ease');
background: white;
&:focus {
outline: $widget-focus-outline;
outline-offset: $widget-focus-outline-offset;
border-bottom-color: $button-submit-color;
}
&.disabled,
&[disabled] {
@ -222,20 +173,10 @@ input, input[type="text"], input[type="url"], input[type="email"], input[type="p
}
}
input[type="text"][name$="_url"], input[type="text"][name$="-url"], input[type="url"] {
width: 100%;
}
input[type="radio"]:focus, input[type="checkbox"]:focus {
box-shadow: none;
}
label input[type="radio"], label input[type="checkbox"] {
&[disabled] + span {
color: lighten($font-color, 30%);
}
}
input[readonly], select[readonly], textarea[readonly] {
border-width: 0 0 1px 0;
}
@ -247,26 +188,19 @@ div.date input[readonly] {
input[type=file] {
border: none;
padding-left: 0;
&:focus:not([readonly]) {
border: none;
}
}
select {
background: white;
appearance: none;
@include vendor-prefix('appearance', 'none');
padding-right: 4em;
background-image: url($data_uri_arrow-down);
background-image: url(arrow-down.svg);
background-position: right 1.3rem center;
background-repeat: no-repeat;
background-size: 1rem auto;
&::-ms-expand {
// remove the arrow of select element in IE
display: none;
}
}
select[multiple] {
select[multiple=multiple] {
background: white;
padding-right: 0;
}
@ -275,7 +209,6 @@ input[type="checkbox"],
input[type="radio"] {
margin-right: 1ex;
margin-bottom: 1ex;
accent-color: $primary-color;
}
div.content label {
@ -292,9 +225,6 @@ span.helptext,
div.hint {
display: block;
font-size: 80%;
p {
margin: 0;
}
}
form p label {
@ -306,7 +236,6 @@ div.a2-block form select {
width: 100%;
}
div.a2-block form input[type=checkbox],
div.a2-block form input[type=radio] {
width: auto;
}
@ -352,7 +281,7 @@ fieldset.gadjo-foldable legend.gadjo-foldable-widget {
}
fieldset.gadjo-foldable legend.gadjo-foldable-widget:after {
content: "";
transition: transform 0.1s ease;
@include vendor-prefix('transition', 'transform 0.1s ease');
position: absolute;
right: 1ex;
}
@ -367,122 +296,6 @@ fieldset.gadjo-foldable {
display: none;
}
/* select2 */
div.select2-container,
span.select2-container {
font-size: 100%;
min-width: 20em;
margin-top: 2px;
a.select2-choice {
padding: 0.1em 0.7em;
}
span.select2-selection--single,
span.select2-selection--multiple,
a.select2-choice,
a.select2-choice div {
box-sizing: content-box;
padding: 1px 0;
background: $widget-background;
color: $widget-color;
border-radius: $widget-border-radius;
border: $widget-border;
.select2-selection__rendered {
color: $widget-color;
}
}
.select2-search--inline .select2-search__field {
margin-top: 0;
margin-bottom: 0;
border: none;
}
&.select2-container--focus,
&.select2-container--open {
span.select2-selection--single,
span.select2-selection--multiple,
a.select2-choice,
a.select2-choice div {
background: $widget-focus-background;
border: $widget-focus-border;
color: $widget-focus-color;
span {
color: $widget-focus-color;
}
}
}
&.select2-container--focus span.select2-selection--single,
&.select2-container--focus span.select2-selection--multiple {
outline: $widget-focus-outline;
outline-offset: $widget-focus-outline-offset;
}
.select2-choices,
.select2-choice {
box-shadow: none;
}
.select2-search--dropdown input,
.select2-search--dropdown input:active,
.select2-search--dropdown input:focus {
background: white;
color: #333;
border: 1px solid #ccc;
}
.select2-selection--single .select2-selection__rendered {
padding-right: 50px;
}
.select2-selection--single .select2-selection__arrow {
background-image: url($data_uri_arrow-down);
background-position: right 1.3rem center;
background-repeat: no-repeat;
background-size: 1rem auto;
width: 50px;
right: 0;
top: 0;
height: 100%;
b {
display: none;
}
}
.select2-selection--single .select2-selection__clear {
margin-right: 2em;
}
.select2-dropdown {
border: $widget-border;
&.select2-dropdown--below {
position: relative;
top: -6px;
}
}
.select2-results {
.loading-results {
position: absolute;
display: inline-block;
right: 0;
color: black;
@media screen and (max-width: $mobile-limit) {
display: none;
}
}
.loading-results:last-child {
position: static;
display: block;
color: inherit;
}
}
}
div.select2-container.select2-drop-above .select2-choice {
background: white;
border-radius: 0;
}
div.select2-drop {
box-shadow: none;
border-radius: 0;
}
div.select2-search {
margin-top: 4px;
}
/* form.as_p */
form p {
@ -528,200 +341,3 @@ form.small button + button,
form.small button + a.button {
margin-left: 1em;
}
[name$="-clear"] + label {
display: inline;
}
.field-live-hint {
position: absolute;
background: #ffffee;
color: #333;
z-index: 1000000;
padding: 1em 1em;
box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.16);
}
.field-live-hint span::before {
font-family: FontAwesome;
content: "\f0eb"; // lightbulb
padding-right: 0.5em;
}
.field-live-hint button.action,
.field-live-hint button.close {
margin: 0 1em;
padding: 0;
color: blue !important;
border: none;
text-decoration: underline !important;
background: transparent !important;
box-shadow: none !important;
}
.field-live-hint button.close {
color: #333 !important;
margin: 0;
text-decoration: none !important;
}
.field-live-hint button.close::after {
content: "×";
}
form {
.widget-optional span.optional {
display: none;
}
}
form.pk-mark-optional-fields {
.widget-required {
span.required {
display: none;
}
}
.widget-optional:not(.django-checkbox-input) span.optional {
display: inline;
font-style: italic;
}
}
form.pk-hide-requisiteness {
.widget-required span.required,
.widget-optional:not(.django-checkbox-input) span.optional {
display: none;
}
}
.gadjo-joined-buttons {
display: inline-flex;
button {
border-radius: 0;
margin-left: -1px; // join borders
&:first-child {
border-radius: 3px 0 0 3px;
margin-left: 0px;
}
&:last-child {
border-radius: 0 3px 3px 0;
}
}
}
.pk-tabs {
display: flex;
flex-direction: row;
&--tab-list {
flex: 0;
display: flex;
justify-content: flex-start;
flex-direction: column;
background: #fafafa;
padding: 0.5em;
button {
border: 0px solid transparent;
border-left-width: 3px;
text-align: left;
font-weight: normal;
background: transparent;
width: 100%;
min-width: 10em;
margin-bottom: 1px;
color: #333;
&:focus {
outline: none;
}
&:focus-visible {
outline: $widget-focus-outline;
}
&:hover {
color: inherit;
background: #eee;
}
&[aria-selected="true"] {
background: #e0e0e0;
border-left-color: $primary-color;
}
&.pk-tabs--button-marker {
padding-right: 2em;
background-size: 5px 5px;
background-repeat: no-repeat;
background-position: top 50% right 1em;
background-image: radial-gradient(closest-side, #888 100%, transparent);
}
}
}
&--container {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
overflow: auto;
background: white;
> * {
padding: 1rem 0.5rem;
}
}
}
.godo:not(.html-edition) .godo--editor {
@extend textarea;
}
/* force alignment for blocks defining grid elements within grids */
.BlockSubWidget.widget {
margin-bottom: 0;
}
.buttons-group {
display: flex;
a {
@extend %button;
margin-right: 0;
margin-left: -1px;
border-radius: 0;
&:first-child {
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
&:last-child {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
&.active {
background: var(--color);
color: white;
}
}
}
.gadjo-password-field {
position: relative;
.title label {
padding-right: 6em;
}
}
.password-visibility-checkbox {
display: flex;
position: absolute;
top: 0;
right: 0;
input + label {
margin: 0;
}
input {
margin: 0 0.25em 0 0;
}
}
.CheckboxesWidget.pk-horizontal-checkboxes .content li {
display: inline-block;
}
.RadiobuttonsWidget.pk-horizontal-radiobuttons .content {
li, label {
display: inline-block;
}
}

View File

@ -1,104 +0,0 @@
// ======
// fx-grid.css
// flexbox grid system
// =====
// Publik vars
$fx-grid-gutter: 1rem;
$fx-grid-gutter-and-epsilon: $fx-grid-gutter + 0.00001rem;
$fx-grid-cell-min-size: 10em; // for .fx-grid--auto
$fx-grid-mobile-limit: $very-small-limit;
$fx-grid-tablet-limit: $grid-mobile-limit;
$max-cols-mobile : 3;
$max-cols-tablet : 6;
$max-cols-desktop : 9;
// custom media queries
// ex. @media ($max-grid-mobile-viewport) {}
$max-grid-mobile-viewport: "max-width: #{$fx-grid-mobile-limit}";
$min-grid-tablet-viewport: "min-width: #{$fx-grid-mobile-limit + 1}";
$min-grid-desktop-viewport: "min-width: #{$fx-grid-tablet-limit + 1}";
.fx-grid,
[class*="fx-grid--"] {
display: flex;
flex-wrap: wrap;
margin: 0;
padding: 0;
margin-left: -1 * $fx-grid-gutter;
/* if flex item are list */
list-style-type: none;
> * {
box-sizing: border-box; // for gadjo
margin-left: $fx-grid-gutter;
flex-basis: calc(100% - #{$fx-grid-gutter});
hyphens: auto;
}
}
// mode auto
.fx-grid--auto {
> * {
flex-basis: $fx-grid-cell-min-size;
flex-shrink: 1;
flex-grow: 1;
}
}
// mode cols
@for $i from 2 through $max-cols-mobile {
.fx-grid--#{$i} > *,
[class*="fx-grid--"][class*="--m#{$i}"] > * {
flex-basis: calc(#{100%/$i} - #{$fx-grid-gutter-and-epsilon});
}
}
@media ($min-grid-tablet-viewport) {
@for $i from 2 through $max-cols-tablet {
[class*="fx-grid--"][class*="--t#{$i}"] > * {
flex-basis: calc(#{100%/$i} - #{$fx-grid-gutter-and-epsilon});
}
}
}
@media ($min-grid-desktop-viewport) {
@for $i from 2 through $max-cols-desktop {
[class*="fx-grid--"][class*="--d#{$i}"] > * {
flex-basis: calc(#{100%/$i} - #{$fx-grid-gutter-and-epsilon});
}
}
}
// custom grid cell size
.fx-grid,
[class*="fx-grid--"] {
@for $i from 1 through $max-cols-mobile {
@for $j from 1 through $i {
> .size--#{$j}-#{$i},
> [class*="size--"][class*="--m#{$j}-#{$i}"] {
flex-basis: calc( #{100%*$j/$i} - #{$fx-grid-gutter-and-epsilon});
flex-grow: 0;
}
}
}
@media ($min-grid-tablet-viewport) {
@for $i from 1 through $max-cols-tablet {
@for $j from 1 through $i {
> [class*="size--"][class*="--t#{$j}-#{$i}"] {
flex-basis: calc( #{100%*$j/$i} - #{$fx-grid-gutter-and-epsilon});
flex-grow: 0;
}
}
}
}
@media ($min-grid-desktop-viewport) {
@for $i from 1 through $max-cols-desktop {
@for $j from 1 through $i {
> [class*="size--"][class*="--d#{$j}-#{$i}"] {
flex-basis: calc( #{100%*$j/$i} - #{$fx-grid-gutter-and-epsilon});
flex-grow: 0;
}
}
}
}
}

View File

@ -1,7 +1,5 @@
@charset "UTF-8";
$grid-mobile-limit: 1024px !default;
$very-small-limit: 560px !default;
$grid-mobile-limit: 601px !default;
$very-small-limit: 401px !default;
div.grid {
float: left;
@ -10,28 +8,6 @@ div.grid {
clear: none;
}
form div[class*=grid-] {
~ h3, ~ h4, ~ p, + div {
clear: both;
}
@media screen and (max-width: $very-small-limit) {
&:not(.never-alone) {
width: 100%;
padding-right: 0;
}
}
table, textarea, select, input:not([type=checkbox]):not([type=radio]) {
width: 100%;
}
.select2-container {
min-width: auto;
width: 100% !important;
}
.select2-selection {
width: 100% !important;
}
}
@each $i in 1, 2, 3, 4, 6, 12 {
@for $j from 1 through $i {
div.grid-#{$j}-#{$i} {
@ -54,6 +30,12 @@ form div[class*=grid-] {
@media screen and (max-width: $very-small-limit) {
width: 100%;
}
& + h3, & + h4, & + p, & + div {
clear: both;
}
table, textarea, select, input[type=text], input[type=password], input[type=email] {
width: 100%;
}
}
body div + div.grid-#{$j}-#{$i}, /* more specific than & + div above*/
div div.grid-#{$j}-#{$i} {

View File

@ -1,5 +1,3 @@
@charset "UTF-8";
/* temporary hacks for applications */
div.form-inner-container, // authentic
@ -7,7 +5,8 @@ div#pages-list, // combo
div.placeholder, // combo
table.agenda-table, // chrono
div#appbar + form, // misc
div#appbar + ul.messages + form, // misc
div#main-content > h2:first-child + form, // w.c.s.
div.form-validation form, // w.c.s.
div#appbar + div#description // passerelle
{
background: white;
@ -16,15 +15,19 @@ div#appbar + div#description // passerelle
box-sizing: border-box;
}
.ui-dialog div.form-inner-container { // authentic
padding: 0;
}
div.other_actions { // authentic
margin-left: 71%;
width: 29%;
}
div div.bo-block ul.biglist { // w.c.s.
margin: -1ex;
}
div div.bo-block ul.biglist p.details.badge { // w.c.s.
background: $primary-color;
}
body.welco-home div#main-content {
background: white;
margin: 0;

View File

@ -1,5 +1,3 @@
@charset "UTF-8";
body .ui-front {
z-index: 1000;
}
@ -192,51 +190,20 @@ div.ui-dialog {
padding: 0.3em 1em 0.5em 0.4em;
.ui-dialog-buttonset {
float: right;
display: flex;
}
button {
margin: 0.5em 0 0.5em 1em;
&.cancel-button {
// always force cancel button to be secondary
order: -1;
}
}
}
form p,
div.widget {
input,
select,
textarea {
width: 100%;
}
input[type=submit], input[type=radio], input[type=checkbox] {
width: auto;
}
form p input,
form p select,
form p textarea {
width: 100%;
}
.helptext {
max-width: 50em;
}
// one line dialog
// add this class on widget to remove titlebar, position the close button to the left of content
&.oneline-dialog {
.ui-dialog-titlebar {
float: right;
padding-top: 5px;
}
.ui-dialog-title {
display: none;
}
.ui-dialog-titlebar-close {
display: block;
}
// visual feedback when open dialog
transition: box-shadow 800ms ease 200ms;
&.feedback-on-open {
box-shadow: $primary-color 0px 0px 20px 2px;
}
form p input[type=radio], form p input[type=checkbox] {
width: auto;
}
}

View File

@ -1,5 +1,3 @@
@charset "UTF-8";
$font-path: '../xstatic/fonts' !default;
@mixin font($type, $weight) {

View File

@ -1,5 +1,3 @@
@charset "UTF-8";
div.cell.shown-because-admin {
opacity: 0.5;
background-image: repeating-linear-gradient(-45deg, #eee 0px, #eee 14px, transparent 15px, transparent 30px);
@ -9,7 +7,7 @@ div.cell.shown-because-admin {
}
}
div#portal-agent-content, aside#sidebar {
div#portal-agent-content {
div.searchcell {
font-size: 110%;
}
@ -17,76 +15,17 @@ div#portal-agent-content, aside#sidebar {
background: white;
padding: 1rem;
margin-bottom: 1rem;
border-radius: $cell-border-radius;
&.transparent, &.pk-transparent {
border-radius: 3px;
&.transparent {
background: transparent;
}
&.highlight, &.pk-highlight {
background: linear-gradient(to right, $primary-color 30%, $secondary-color 100%);
&.highlight {
background: linear-gradient(to right, $primary-color 0%, $secondary-color 130vh);
color: white;
h2, a {
h2 {
color: white;
}
}
&.no-bottom-margin {
margin-bottom: 0;
border-radius: $cell-border-radius $cell-border-radius 0 0;
border-bottom: 0;
p:last-child {
margin-bottom: 0;
padding-bottom: 1ex;
}
+ div {
margin-top: 0;
border-radius: 0 0 $cell-border-radius $cell-border-radius;
border-top: 0;
&.no-bottom-margin {
border-radius: 0;
}
p:first-child {
margin-top: 0;
padding-top: 1ex;
}
}
}
&.pk-button, &.pk-big-button,
&[class*=pk-button-], &[class*="pk-big-button-"] { // when used on link cells
padding: 0;
a {
@extend %button;
text-align: center;
display: block;
}
}
&.pk-big-button,
&[class*="pk-big-button-"] {
a {
padding: 2rem 4rem;
}
}
&.pk-button-cancel, &.pk-big-button-cancel {
a {
@extend %cancel-button;
}
}
&.pk-button-delete, &.pk-big-button-delete {
a {
@extend %delete-button;
}
}
&.pk-button-submit, &.pk-big-button-submit {
a {
@extend %submit-button;
}
}
}
}
aside#sidebar {
div.cell {
background: white;
padding: 0 1rem;
margin-top: 1rem;
}
}
@ -96,36 +35,3 @@ div.combo-search-results {
border-bottom-color: transparent;
}
}
.link-list-cell.pk-horizontal-button-links,
.link-list-cell.pk-wide-horizontal-button-links {
ul {
display: flex;
@media screen and (max-width: $mobile-limit) {
flex-direction: column;
}
}
li {
&:not(:last-child) {
margin-right: 1em;
}
border: none;
&:hover {
background: transparent;
}
@media screen and (max-width: $mobile-limit) {
&:not(:last-child) {
margin-right: 0;
}
margin-bottom: 0.5em;
}
}
&.pk-wide-horizontal-button-links {
li {
flex: 1;
}
}
a {
@extend %button;
}
}

View File

@ -1,5 +1,3 @@
@charset "UTF-8";
@font-face {
font-family: 'FontAwesome';
src: url('../xstatic/fonts/fontawesome-webfont.eot');
@ -8,6 +6,12 @@
font-style: normal;
}
@mixin vendor-prefix($name, $value) {
@each $vendor in ('-webkit-', '-moz-', '-ms-', '-o-', '') {
#{$vendor}#{$name}: #{$value};
}
}
@function text-color($color) {
@if (lightness($color) > 50) {
@return #303030;
@ -15,20 +19,3 @@
@return #ffffff;
}
}
// Only display content to screen readers
@mixin sr-only {
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important;
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
}
.sr-only {
@include sr-only();
}

View File

@ -0,0 +1,77 @@
$actions: add, duplicate, edit, remove;
#sidebar div#sticky-sidebar {
width: calc(100% - 2rem);
}
div#side { // w.c.s. steps in backoffice submission
background: white;
padding: 0.5rem;
border-radius: 3px 3px 0 0;
& + form {
background: white;
padding: 0.5rem;
border-radius: 0 0 3px 3px;
}
#steps ol {
background: transparent;
.current span.marker {
background: $primary-color;
border-color: darken($primary-color, 20%);
}
}
}
#main ul#fields-list li {
padding-top: 6px;
}
#main ul.biglist li p.commands span {
padding: 0;
box-shadow: none;
border: none;
a {
@extend %button;
font-weight: normal;
}
&.view {
margin-top: 2px;
}
&.remove, &.add, &.edit, &.duplicate {
padding: 0;
border: 0;
background: transparent;
box-shadow: none;
a {
border: none;
padding: 6px;
display: inline-block;
text-indent: -10000px;
overflow: hidden;
width: 30px;
}
}
@each $action in $actions {
&.#{$action} a {
background: url(icons/action-#{$action}.small.#{$string-color}.png) center center no-repeat;
&:hover {
background-image: url(icons/action-#{$action}.hover.png);
}
}
}
}
div.form-validation form div.page {
border: none;
}
div.workflow-messages > div,
div.workflow-messages > p {
background: white;
margin: 1ex 0;
padding: 1ex;
}
div.buttons > div.widget {
margin-right: 1rem;
}

View File

@ -1,35 +0,0 @@
.gadjo-multi-select-widget {
&--field {
margin-bottom: 0.2em;
}
&--select-button-container {
display: flex;
gap: 0.5em;
}
&--field {
select {
min-width: 0;
}
button {
margin-top: auto;
margin-bottom: auto;
}
&:first-of-type .gadjo-multi-select-widget--button-remove {
display: none;
}
}
&--button-add::before {
content: "\f067"; /* plus */
font-family: FontAwesome;
}
&--button-remove::before {
content: "\f068"; /* minus */
font-family: FontAwesome;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
p.snapshot-description {
font-size: 80%;
margin: 0;
}
table.diff {
background: white;
border: 1px solid #f3f3f3;
border-collapse: collapse;
width: 100%;
colgroup, thead, tbody, td {
border: 1px solid #f3f3f3;
}
tbody tr:nth-child(even) {
background: #fdfdfd;
}
th, td {
max-width: 30vw;
/* it will not actually limit width as the table is set to
* expand to 100% but it will prevent one side getting wider
*/
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top;
}
.diff_header {
background: #f7f7f7;
}
td.diff_header {
text-align: right;
padding-right: 10px;
color: #606060;
}
.diff_next {
display: none;
}
.diff_add {
background-color: #aaffaa;
}
.diff_chg {
background-color: #ffff77;
}
.diff_sub {
background-color: #ffaaaa;
}
.difflib_chg_to td {
background-color: #f7f7f7;
}
.expand-handler td {
text-align: left;
background-color: #f7f7f7;
&:hover {
background-color: inherit;
}
}
.expand-before, .expand-between, .expand-after {
cursor: pointer;
&::before {
font-family: FontAwesome;
padding: 0 2ex;
}
}
.expand-before::before {
content: "\f176"; // long-arrow-up
}
.expand-between::before {
content: "\f07d"; // arrows-v
}
.expand-after::before {
content: "\f175"; // long-arrow-down
}
}
div.snapshot-diff {
margin: 1em 0;
display: none;
ins {
text-decoration: none;
background-color: #d4fcbc;
}
del {
text-decoration: line-through;
background-color: #fbb6c2;
color: #555;
}
h3 {
del, ins {
font-weight: bold;
background-color: transparent;
}
del, del a {
color: #fbb6c2 !important;
}
ins, ins a {
color: #d4fcbc !important;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,102 +0,0 @@
<?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"
width="13"
height="13"
viewBox="0 0 3.4395833 3.4395832"
version="1.1"
id="svg3125"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="info-icon.svg"
inkscape:export-filename="info-icon.png"
inkscape:export-xdpi="590.77002"
inkscape:export-ydpi="590.77002">
<defs
id="defs3119" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="1.5869111"
inkscape:cy="4.5592662"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="836"
inkscape:window-x="179"
inkscape:window-y="1107"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:guide-bbox="true"
units="px">
<sodipodi:guide
position="-1.5957682,0.36380207"
orientation="1,0"
id="guide819"
inkscape:locked="false" />
<sodipodi:guide
position="-0.52916665,-0.52916665"
orientation="1,0"
id="guide821"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata3122">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-51.743849,-118.88301)">
<path
inkscape:connector-curvature="0"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#386ede;stroke-width:0.09999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 53.463641,118.95313 c -0.606618,0 -1.098382,0.4916 -1.098382,1.09802 0,0.40605 0.221383,0.75363 0.549192,0.9436 v 0.70343 h 1.098382 v -0.70343 c 0.327809,-0.18997 0.54919,-0.53755 0.54919,-0.9436 0,-0.60642 -0.491765,-1.09802 -1.098382,-1.09802 z"
id="path4561"
sodipodi:nodetypes="csccccsc" />
<path
inkscape:connector-curvature="0"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:#386ede;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 52.991534,122.24009 h 0.944213"
id="path4488-4"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:#386ede;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 52.862851,121.96715 1.201579,0.002"
id="path4488-4-7"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.8;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#386ede;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 53.199057,120.20164 h 0.529167"
id="path4488-4-4"
sodipodi:nodetypes="cc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
width="13"
height="13"
viewBox="0 0 3.4395833 3.4395832"
version="1.1"
id="svg3125"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="sorry-icon.svg"
inkscape:export-filename="sorry-icon.png"
inkscape:export-xdpi="590.77002"
inkscape:export-ydpi="590.77002">
<defs
id="defs3119" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.318002"
inkscape:cx="-3.332695"
inkscape:cy="4.729909"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="836"
inkscape:window-x="179"
inkscape:window-y="1107"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:guide-bbox="true"
units="px"
inkscape:document-rotation="0">
<sodipodi:guide
position="-1.5957682,0.36380207"
orientation="1,0"
id="guide819"
inkscape:locked="false" />
<sodipodi:guide
position="-0.52916665,-0.52916665"
orientation="1,0"
id="guide821"
inkscape:locked="false" />
<sodipodi:guide
position="0.85704491,2.416597"
orientation="0,-1"
id="guide863" />
<sodipodi:guide
position="0.79428574,1.8879927"
orientation="0,-1"
id="guide865" />
</sodipodi:namedview>
<metadata
id="metadata3122">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-51.743849,-118.88301)">
<path
inkscape:connector-curvature="0"
d="m 53.72296,120.7007 c -7.93e-4,-0.86144 0.229902,-1.32314 0.370795,-1.32327 l 0.132292,-1.3e-4 c -0.168259,0.26383 -0.238755,1.06292 -0.238503,1.32315 2.51e-4,0.26022 -0.01545,1.00664 0.241054,1.32268 l -0.132292,1.3e-4 c -0.180176,1.7e-4 -0.372515,-0.46112 -0.373346,-1.32256 z"
id="rect3773-4"
style="display:inline;opacity:1;fill:#386ede;fill-opacity:1;stroke:none;stroke-width:0.264583"
sodipodi:nodetypes="cccsccc" />
<circle
style="color:#000000;overflow:visible;opacity:1;fill:#386ede;fill-opacity:1;stroke-width:0.15875;stroke-linejoin:round;stroke-miterlimit:10"
id="path842"
cx="53.208046"
cy="121.22882"
r="0.25790736" />
<circle
style="color:#000000;overflow:visible;opacity:1;fill:#386ede;fill-opacity:1;stroke-width:0.15875;stroke-linejoin:round;stroke-miterlimit:10"
id="path842-3"
cx="53.208046"
cy="120.17593"
r="0.25790736" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,6 +1,6 @@
var gadjo_js = gadjo_js || {};
(function () {
if (gadjo_js.loaded) return;
if (gadjo_js.loaded) return
gadjo_js.loaded = true;
var $ = jQuery;
var popup_script_loaded = {};
@ -47,9 +47,6 @@ var gadjo_js = gadjo_js || {};
* attribute, a gadjo:dialog-done event is triggered on success, a
* gadjo:dialog-submit-error event is triggered on failure.
*
* Set data-autoclose-dialog="true" to close the dialog box after the
* submit.
*
* Dialog is modal by default, set data-modal="false" for non-modal
* dialogs.
*/
@ -58,7 +55,6 @@ var gadjo_js = gadjo_js || {};
var selector = $anchor.data('selector') || 'form:not(.gadjo-popup-ignore)';
var title_selector = $anchor.data('title-selector') || '#appbar h2';
var inplace_submit = $anchor.data('inplace-submit');
var autoclose_dialog = $anchor.data('autoclose-dialog');
var modal = $anchor.data('modal');
if (url == '#') {
return false;
@ -82,7 +78,7 @@ var gadjo_js = gadjo_js || {};
function ajaxform_submit(data, status, xhr, form) {
if ('location' in data) {
var e = $.Event('gadjo:dialog-done');
if (document.body.contains($anchor[0])) {
if (document.contains($anchor[0])) {
$anchor.trigger(e, data);
} else {
$(document).trigger(e, data);
@ -99,7 +95,7 @@ var gadjo_js = gadjo_js || {};
var $form = $(form);
$form.empty().append($(data.content).find(selector).children());
$form.find('.buttons').hide();
if (document.body.contains($anchor[0])) {
if (document.contains($anchor[0])) {
$anchor.trigger('gadjo:dialog-loaded', $form);
} else {
$(document).trigger('gadjo:dialog-loaded', $form);
@ -112,7 +108,6 @@ var gadjo_js = gadjo_js || {};
$.ajax({
url: url,
beforeSend: function(xhr) {xhr.setRequestHeader('X-Popup', 'true'); },
success: function(html) {
var is_json = typeof html != 'string';
if (is_json) {
@ -165,15 +160,10 @@ var gadjo_js = gadjo_js || {};
/* get title out of html */
var title = $html.find(title_selector).text();
/* force textarea width so the dialog is sized to properly
* embed the ckeditor widget. */
$content.find('textarea[data-config]').attr('cols', '80');
$content.dialog({
modal: modal,
'title': title,
width: 'auto',
closeText: $anchor.data('close-button-text') || 'Close',
close: function (ev, ui) {
$(this).dialog('destroy');
},
@ -197,8 +187,7 @@ var gadjo_js = gadjo_js || {};
if ($elem.prop('disabled')) {
button.disabled = 'disabled';
}
var is_cancel_button = $elem.hasClass('cancel') || $elem.hasClass('cancel-button') || $elem.is('[name="cancel"]');
if (is_cancel_button) {
if ($elem.hasClass('cancel')) {
/* special behaviour for the cancel button: do not send
* anything to server, just close the dialog */
button.click = function() { $content.dialog('destroy'); return false; };
@ -217,7 +206,7 @@ var gadjo_js = gadjo_js || {};
type: 'POST',
url: action_url,
data: $form.serialize(),
}).done(function(data) {
}).success(function(data) {
$anchor.trigger('gadjo:dialog-done', data);
$content.dialog('destroy');
}).fail(function() { $anchor.trigger('gadjo:dialog-submit-error');
@ -228,15 +217,6 @@ var gadjo_js = gadjo_js || {};
} else {
$elem.click();
}
var validated = true;
$form.find('input, textarea').each(function() {
if ($(this)[0].checkValidity != undefined) {
validated &= $(this)[0].checkValidity();
}
})
if (autoclose_dialog & validated) {
$content.dialog('destroy');
}
}
return false;
};
@ -245,9 +225,9 @@ var gadjo_js = gadjo_js || {};
/* add custom classes to some buttons */
if ($elem.hasClass('submit-button')) {
button.class = 'submit-button';
} else if (is_cancel_button) {
} else if ($elem.hasClass('cancel') || $elem.hasClass('cancel-button')) {
button.class = 'cancel-button';
} else if ($elem.hasClass('delete-button') || $elem.is('[name=delete]')) {
} else if ($elem.hasClass('delete-button')) {
button.class = 'delete-button';
}
buttons.push(button);
@ -257,9 +237,8 @@ var gadjo_js = gadjo_js || {};
$content.dialog('option', 'buttons', buttons);
/* focus initial input field */
var $form_fields = $form.find('input:visible, textarea:visible, select:visible');
if ($form_fields.length) {
$form_fields[0].focus();
if ($form.find('input:visible').length) {
$form.find('input:visible')[0].focus();
}
/* if received content was in json, apply jQuery Form plugin on it */
@ -282,99 +261,6 @@ var gadjo_js = gadjo_js || {};
return false;
}
// Tabs
// adapted from https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tab_Role
gadjo_js.Tabs = function(tabs_el) {
this.parent = tabs_el;
this.tabList = this.parent.querySelector('[role="tablist"]');
this.tabs = this.tabList.querySelectorAll('[role="tab"]');
this.tabpanels = this.parent.querySelectorAll('[role="tabpanel"]');
this.init();
}
gadjo_js.Tabs.prototype = {
init : function() {
const _self = this;
// Add a click event handler to each tab
this.tabs.forEach(function(tab) {
tab.addEventListener('click', function(e) {_self.selectTab.call(_self, e)});
});
// Enable arrow navigation between tabs in the tab list
let tabFocus = 0;
this.tabList.addEventListener('keydown', function(e) {
// Move up & down
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
e.preventDefault();
_self.tabs[tabFocus].setAttribute('tabindex', -1);
if (e.key === "ArrowDown") {
tabFocus++;
// If we're at the end, go to the start
if (tabFocus >= _self.tabs.length) {
tabFocus = 0;
}
} else if (e.key === "ArrowUp") {
tabFocus--;
// If we're at the start, move to the end
if (tabFocus < 0) {
tabFocus = _self.tabs.length - 1;
}
}
_self.tabs[tabFocus].setAttribute('tabindex', 0);
_self.tabs[tabFocus].focus();
}
});
},
selectTab: function(e) {
const btn = e.target && e.target || e;
// Remove all current selected tabs
this.tabList
.querySelectorAll('[aria-selected="true"]')
.forEach(function(t) { t.setAttribute('aria-selected', false); });
// Set this tab as selected
btn.setAttribute('aria-selected', true);
// Hide all tab panels
this.tabpanels.forEach(function(p) { p.hidden = true });
// Show the selected panel
this.parent
.querySelector('#' + btn.getAttribute('aria-controls'))
.hidden = false;
// Adjust URL to mention selected tab
const url = new URL(document.location);
const prefix = btn.getAttribute('aria-controls').split('-')[0];
url.hash = '#open:' + btn.getAttribute('aria-controls').substring(prefix.length + 1);
history.replaceState(null, '', url);
// Trigger gadjo:tab-selected event on panel
$(this.parent.querySelector('#' + btn.getAttribute('aria-controls'))).trigger('gadjo:tab-selected');
return false;
}
}
window.addEventListener('DOMContentLoaded', function() {
$(document.querySelectorAll('.pk-tabs')).each(function(i, el) {
el.tabs = new gadjo_js.Tabs(el);
});
/* focus tab from #open:<tab slug> anchor, to point to open panel */
if (document.location.hash && document.location.hash.indexOf('#open:') == 0) {
const $tab_button = $('#tab-' + document.location.hash.substring(6) + '[role=tab]');
if ($tab_button.length) {
$tab_button.parents('.pk-tabs')[0].tabs.selectTab($tab_button[0]);
}
}
});
var storage = undefined;
try {
window.localStorage._gadgo_test = true;
@ -390,63 +276,50 @@ var gadjo_js = gadjo_js || {};
}
}
var cookie_domain = window.location.hostname.split('.').slice(1).join('.');
function readCookie(name) { /* http://www.quirksmode.org/js/cookies.html */
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function set_sidepage_status(sidepage_status) {
storage.sidepage_status = sidepage_status;
if (cookie_domain) {
var date = new Date();
date.setTime(date.getTime() + (10 * 86400 * 1000)); /* a long week */
document.cookie = 'gadjo_sidepage_status=' + sidepage_status +
'; expires=' + date.toGMTString() +
(window.location.protocol == "https:" && "; Secure" || "") +
'; sameSite=Strict' +
'; domain=.' + cookie_domain +
'; path=/';
}
}
function get_sidepage_status() {
if (window.location.protocol == 'file:') {
/* don't open sidepage when loading from a file:// */
return 'collapsed';
}
var sidepage_status = null;
if (cookie_domain) {
sidepage_status = readCookie('gadjo_sidepage_status');
} else {
sidepage_status = storage.sidepage_status;
}
if (!sidepage_status &&
typeof(GADJO_DEFAULT_SIDEPAGE_STATUS) !== "undefined") {
return GADJO_DEFAULT_SIDEPAGE_STATUS;
}
return sidepage_status;
}
document.addEventListener('DOMContentLoaded', function() {
if (document.body.dataset.gadjo === 'true' && document.getElementById('sidepage')) {
document.body.setAttribute('data-has-sidepage', 'true');
if (storage.gadjo_sidebar_menu) {
$('#sidepage-menu').empty().append($(storage.gadjo_sidebar_menu));
}
if (window.innerWidth > 760 && get_sidepage_status() == 'expanded') {
document.body.className += ' sidepage-expanded';
}
}
});
$(function() {
$(document).on('click.gadjo', 'a[rel=popup], a[data-popup]', displayPopup);
var cookie_domain = window.location.hostname.split('.').slice(1).join('.');
function readCookie(name) { /* http://www.quirksmode.org/js/cookies.html */
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function set_sidepage_status(sidepage_status) {
storage.sidepage_status = sidepage_status;
if (cookie_domain) {
var date = new Date();
date.setTime(date.getTime() + (10 * 86400 * 1000)); /* a long week */
document.cookie = 'gadjo_sidepage_status=' + sidepage_status +
'; expires=' + date.toGMTString() +
'; domain=.' + cookie_domain +
'; path=/';
}
}
function get_sidepage_status() {
if (window.location.protocol == 'file:') {
/* don't open sidepage when loading from a file:// */
return 'collapsed';
}
var sidepage_status = null;
if (cookie_domain) {
sidepage_status = readCookie('gadjo_sidepage_status');
} else {
sidepage_status = storage.sidepage_status;
}
if (!sidepage_status &&
typeof(GADJO_DEFAULT_SIDEPAGE_STATUS) !== "undefined") {
return GADJO_DEFAULT_SIDEPAGE_STATUS;
}
return sidepage_status;
}
$(document).on('click.gadjo', 'a[rel=popup]', displayPopup);
if ($('#sidepage').length) {
var sidepage_button = $('#sidepage #applabel');
sidepage_button.on('click', function() {
@ -457,11 +330,12 @@ var gadjo_js = gadjo_js || {};
} else {
set_sidepage_status('collasped');
}
setTimeout(function() {
// delay to get the CSS transition to run
$(window).trigger('gadjo:sidepage-toggled');
}, 500);
});
if ($(window).width() > 760) {
if (get_sidepage_status() == 'expanded') {
$('body').toggleClass('sidepage-expanded');
}
}
}
});
$(function () { /* foldable elements with memory */
@ -481,23 +355,17 @@ var gadjo_js = gadjo_js || {};
sessionStorage['gadjo-foldable-id-' + $parent[0].id + '-' + window.location.pathname] = ! $parent.is('.gadjo-folded');
}
});
document.querySelectorAll('details.gadjo-remember-open-status').forEach(
el => {
const key = 'gadjo-foldable-id-' + el.id + '-' + window.location.pathname
if (sessionStorage[key] !== undefined) el.open = (sessionStorage[key] === "true")
el.addEventListener('toggle', (e) => sessionStorage[key] = el.open)
}
)
});
$(function () { /* foldable sections */
$('.section.foldable:not(.gadjo-foldable-ignore) > h2, .section.foldable:not(.gadjo-foldable-ignore) > h3').on('click', function() {
$('.section.foldable > h2, .section.foldable > h3').on('click', function() {
$(this).parent().toggleClass('folded');
});
});
$(function () {
if ($('body').data('gadjo')) {
if ($('#sidepage').length == 1) {
$('body').attr('data-has-sidepage', 'true');
}
/* add × to close notification messages */
$('.messages > li').each(function(idx, elem) {
var elem = $('<a aria-hidden="true" class="close">×</a>');
@ -508,69 +376,11 @@ var gadjo_js = gadjo_js || {};
});
}
});
function prepare_kebab_menu() {
$(document.querySelectorAll('.extra-actions-menu')).each(function(i, el) {
this.setAttribute('id', 'extra-actions-menu'+i);
});
$(document.querySelectorAll('.extra-actions-menu-opener')).each(function(i, el) {
if (this.__initialized === true) return;
// closes all kebab menus which are not the one with lst_id id
function close_others(lst_id) {
$(document.querySelectorAll('.extra-actions-menu')).each(function(i, el) {
if(el.id == lst_id) { return ; }
$(this).removeClass('open')
$('[aria-controls='+el.id+']').attr('aria-expanded', 'false')
$('[aria-controls='+el.id+']').removeClass('open')
})
}
const ctrl_id = 'extra-actions-menu'+i;
this.__initialized = true;
this.setAttribute('tabindex', 0);
this.setAttribute('aria-label', 'Menu'); // XXX: translation
this.setAttribute('aria-controls', ctrl_id);
this.setAttribute('aria-expanded', 'false');
this.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ' ') {
close_others(ctrl_id);
$(function() {
$('a.extra-actions-menu-opener').on('click', function() {
$(this).toggleClass('open');
$('#'+ctrl_id).toggleClass('open');
this.setAttribute('aria-expanded', $(this).is('.open'));
e.preventDefault();
}
$('.extra-actions-menu').toggleClass('open');
});
this.addEventListener('click', function() {
close_others(ctrl_id);
$(this).toggleClass('open');
$('#'+ctrl_id).toggleClass('open');
this.setAttribute('aria-expanded', $(this).is('.open'));
});
});
}
$(function() {
prepare_kebab_menu();
});
$(document).on('gadjo:content-update', prepare_kebab_menu);
$(function() {
$(document).on('click auxclick', '.clickable-rows tr', function(event) {
var $target = $(event.target);
if ($target.is('input, button, a')) {
return true;
}
if (window.getSelection().toString()) {
return false;
}
var href = $(this).data('url') || $(this).find('a[href]').prop('href');
if (href) {
if (event.which == 2 || event.ctrlKey) {
window.open(href, '_blank');
} else {
window.location = href;
}
return false;
}
});
});
$(function() {
$('.varname').on('click', function() {
@ -589,7 +399,4 @@ var gadjo_js = gadjo_js || {};
return false;
});
});
$(document).on('publik:menu-loaded', function() {
storage.gadjo_sidebar_menu = document.getElementById('sidepage-menu').innerHTML;
});
})();

View File

@ -1,58 +0,0 @@
const multiSelectWidget = (function () {
const addRow = function () {
const widget = this.closest('.gadjo-multi-select-widget')
event.preventDefault()
/* get last row node */
const rows = widget.querySelectorAll('.gadjo-multi-select-widget--field')
const lastRow = rows[rows.length - 1]
/* clone the row */
const newRow = lastRow.cloneNode(true)
/* set new label and ids */
const rowLabel = widget.dataset.rowLabel
const newLabel = rowLabel + ' ' + rows.length
newRow.querySelector('label').textContent = newLabel
const rowId = widget.dataset.rowId
const newId = rowId + '_' + rows.length
newRow.querySelector('label').setAttribute('for', newId)
newRow.querySelector('select').setAttribute('id', newId)
/* add new row after the last row */
lastRow.parentNode.insertBefore(newRow, lastRow.nextSibling)
const removeButton = newRow.querySelector('.gadjo-multi-select-widget--button-remove')
removeButton.addEventListener('click', removeRow)
}
const removeRow = function (event) {
event.preventDefault()
const field = this.closest('.content')
let row = this.closest('.gadjo-multi-select-widget--field')
row.remove()
field.dispatchEvent(new Event('change'))
}
const init = function (container) {
const widgets = container.querySelectorAll('.gadjo-multi-select-widget')
if (!widgets.length) return
widgets.forEach(function (widget) {
const deletBtn = widget.querySelectorAll('.gadjo-multi-select-widget--button-remove')
const addBtn = widget.querySelector('.gadjo-multi-select-widget--button-add')
addBtn.removeEventListener('click', addRow)
addBtn.addEventListener('click', addRow)
deletBtn.forEach(btn => btn.removeEventListener('click', removeRow))
deletBtn.forEach(btn => btn.addEventListener('click', removeRow))
})
}
return {
init,
}
})()
window.addEventListener('DOMContentLoaded', () => multiSelectWidget.init(document))

View File

@ -1,69 +0,0 @@
const $ = window.$
$(function () {
$('div.snapshot-diff tr').each(function () {
let $tr = $(this)
if (!$tr.find('.diff_add, .diff_chg, .diff_sub').length) {
return
}
// mark 3 lines before and after each change
$tr.addClass('no-collapse')
.prev().addClass('no-collapse')
.prev().addClass('no-collapse')
.prev().addClass('no-collapse')
$tr
.next().addClass('no-collapse')
.next().addClass('no-collapse')
.next().addClass('no-collapse')
})
$('div.snapshot-diff tr').each(function () {
let $tr = $(this)
if (!$tr.find('.diff_next a').length) {
return
}
let trId = $tr.find('a').first().attr('href').substring(1)
// collapse previous lines
let previousLines = $tr.prevUntil('.difflib_chg_to')
previousLines.each(function () {
let $line = $(this)
if ($line.hasClass('no-collapse') || $line.hasClass('expand-handler')) {
return
}
$line.addClass(trId).addClass('difflib_chg_to').hide()
})
// add expand
if ($tr.prevAll('.difflib_chg_to').first().hasClass(trId)) {
let expandClass = 'expand-between'
if ($tr.prevAll('.difflib_chg_to').first().prevAll('.no-collapse').length === 0) {
expandClass = 'expand-before'
}
$('<tr class="expand-handler"></tr>')
.html(
'<td colspan="6" class="diff_header expand ' + expandClass + '" data-expand="' + trId + '"></td>',
)
.insertAfter($tr.prevAll('.difflib_chg_to').first())
}
// if last change
if ($tr.find('a').first().text() === 't') {
// collapse next lines
let nextLines = $tr.nextAll()
nextLines.each(function () {
let $line = $(this)
if ($line.hasClass('no-collapse') || $line.hasClass('expand-handler')) {
return
}
$line.addClass(trId + '-end').addClass('difflib_chg_to').hide()
})
// add expand
$('<tr class="expand-handler"></tr>')
.html('<td colspan="6" class="diff_header expand expand-after" data-expand="' + trId + '-end"></td>')
.insertAfter($tr.nextAll('.difflib_chg_to').first())
}
})
$('div.snapshot-diff').show()
$(document).on('click', '.expand-handler', function () {
let $handler = $(this)
$handler.hide()
let expandClass = $handler.find('td.expand').first().data('expand')
$('.' + expandClass).show()
})
})

View File

@ -1 +0,0 @@
<label>{% include "django/forms/widgets/input.html" %}<span></span></label>

View File

@ -1 +0,0 @@
{% if widget.wrap_label %}<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} <span>{{ widget.label }}</span></label>{% endif %}

View File

@ -1,26 +1,34 @@
{% load i18n %}
{% if form.errors %}
<div class="errornotice" tabindex="-1" autofocus role="alert">
<p>{% trans "There were errors processing your form." %}</p>
{% for error in form.non_field_errors %}
<p>{{ error }}</p>
{% endfor %}
{% for field in form %}
{% if field.is_hidden and field.errors %}
<p>
{% for error in field.errors %}
{% blocktrans with name=field.name %}(Hidden field {{name}}) {{ error }}{% endblocktrans %}
{% if not forloop.last %}<br>{% endif %}
{% endfor %}
</p>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% for field, widget_template in fields_with_templates %}
{{ form.non_field_errors }}
{% for field in form %}
{% if field.is_hidden %}
{% if field.errors %}
<ul class="errorlist">
{% for error in field.errors %}
<li>
{% blocktrans with name=field.name %}(Hidden field {{name}}) {{ error }}{% endblocktrans %}
</li>
{% endfor %}
</ul>
{% endif %}
{{ field }}
{% else %}
{% include widget_template with field=field %}
{% endif %}
{% endfor %}
{% for field in form %}
{% if not field.is_hidden %}
<p {% if field.css_classes %}class="{{ field.css_classes }}"{% endif %}>
{{ field.label_tag }}
{% if field.errors %}
<ul class="errorlist">
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{{ field }}
{% if field.help_text %}
<span class="helptext">{{ field.help_text }}</span>
{% endif %}
</p>
{% endif %}
{% endfor %}

View File

@ -7,51 +7,35 @@ Expected context variables:
- page_obj: Paginator page object
- page_key (optional): name of page parameter (default: page)
- anchor (optional): anchor to use in links
- without_key (optional): key to remove in GET params
{% endcomment %}
{% if page_obj.paginator.num_pages > 1 %}
{% with page_key=page_key|default:"page" %}
{% spaceless %}
<p class="paginator">
{% if page_obj.number > 4 %}
<a href="{% querystring page_key=1 without without_key %}{{ anchor }}">1</a>
{% else %}
{% if page_obj.number >= 3 %}
<a href="{% querystring page_key=1 without without_key %}{{ anchor }}">1</a>
{% if page_obj.number == 4 %}
<a href="{% querystring page_key=2 without without_key %}{{ anchor }}">2</a>
{% endif %}
{% endif %}
{% endif %}
{% with page_key=page_key|default:"page" %}
{% spaceless %}
<p class="paginator">
{% if page_obj.number > 1 %}
{% if page_obj.previous_page_number != 1 %}
<a href="{% querystring page_key=1 %}{{ anchor }}">1</a>
{% endif %}
{% endif %}
{% if page_obj.has_previous %}
<a href="{% querystring page_key=page_obj.previous_page_number without without_key %}{{ anchor }}">{{ page_obj.previous_page_number }}</a>
{% endif %}
{% if page_obj.has_previous %}
<a href="{% querystring page_key=page_obj.previous_page_number %}{{ anchor }}">{{ page_obj.previous_page_number }}</a>
{% endif %}
<span class="this-page">{{ page_obj.number }}</span>
<span class="this-page">{{ page_obj.number }}</span>
{% if page_obj.has_next %}
<a href="{% querystring page_key=page_obj.next_page_number without without_key %}{{ anchor }}">{{ page_obj.next_page_number }}</a>
{% endif %}
{% if page_obj.number < page_obj.paginator.num_pages|add:"-3" %}
{% if page_obj.next_page_number != page_obj.paginator.num_pages %}
<a href="{% querystring page_key=page_obj.paginator.num_pages without without_key %}{{ anchor }}">{{ page_obj.paginator.num_pages }}</a>
{% endif %}
{% else %}
{% if page_obj.number <= page_obj.paginator.num_pages|add:"-2" %}
{% if page_obj.number == page_obj.paginator.num_pages|add:"-3" %}
{% with a_page_key=page_obj.paginator.num_pages|add:"-1" %}
<a href="{% querystring page_key=a_page_key without without_key %}{{ anchor }}">{{ a_page_key }}</a>
{% endwith %}
{% endif %}
<a href="{% querystring page_key=page_obj.paginator.num_pages without without_key %}{{ anchor }}">{{ page_obj.paginator.num_pages }}</a>
{% endif %}
{% endif %}
</p>
{% endspaceless %}
{% endwith %}
{% if page_obj.has_next %}
<a href="{% querystring page_key=page_obj.next_page_number %}{{ anchor }}">{{ page_obj.next_page_number }}</a>
{% endif %}
{% if page_obj.number != page_obj.paginator.num_pages %}
{% if page_obj.next_page_number != page_obj.paginator.num_pages %}
<a href="{% querystring page_key=page_obj.paginator.num_pages %}{{ anchor }}">{{ page_obj.paginator.num_pages }}</a>
{% endif %}
{% endif %}
</p>
{% endspaceless %}
{% endwith %}
{% endif %}

View File

@ -1,25 +0,0 @@
{% extends "gadjo/widget.html" %}
{% load i18n %}
{% block widget-css-classes %}{{ block.super }} gadjo-password-field{% endblock %}
{% block widget-bottom %}
<div class="password-visibility-checkbox">
<input id="password-visibility-checkbox-{{ field.id_for_label }}" type="checkbox" aria-label="{% trans "Display password" %}">
<label for="password-visibility-checkbox-{{ field.id_for_label }}">{% trans "Display" %}</label>
</div>
<script>
(function() {
const checkbox = document.getElementById('password-visibility-checkbox-{{ field.id_for_label }}');
const password_input = document.querySelector('#{{field.id_for_label}}_p input[type=password]');
checkbox.addEventListener('change', function(e) {
if (this.checked) {
password_input.type = 'text';
} else {
password_input.type = 'password';
}
});
checkbox.checked = false; // force to be hidden on load
})();
</script>
{% endblock %}

View File

@ -1,9 +0,0 @@
{% extends "gadjo/widget.html" %}
{% block widget-attrs %}role="radiogroup"{% endblock %}
{% block widget-control %}
{% for option in field %}
{{ option }}
{% endfor %}
{% endblock %}

View File

@ -1,118 +1,124 @@
{% load i18n gadjo static %}<!DOCTYPE html>
<html {% if LANGUAGE_CODE %}lang="{{ LANGUAGE_CODE }}"{% endif %} {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
{% load i18n gadjo staticfiles %}<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>{% block page-title %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
{% block gadjo-favicon %}
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
{% endblock %}
{% block gadjo-css %}
<link rel="stylesheet" type="text/css" media="all" href="{% static "css/gadjo.css" %}?{% start_timestamp %} "/>
<link rel="stylesheet" type="text/css" media="all" href="{% static "css/gadjo.css" %}?{% start_timestamp %} "/>
{% block css %}
<link rel="stylesheet" type="text/css" media="all" href="{% static "css/style.css" %}?{% start_timestamp %}"/>
<link rel="stylesheet" type="text/css" media="all" href="{% static "css/style.css" %}?{% start_timestamp %}"/>
{% endblock %}
{% endblock %}
{% block gadjo-js %}
<script src="{% xstatic 'jquery' 'jquery.min.js' %}"></script>
<script src="{% xstatic 'jquery-ui' 'jquery-ui.min.js' %}"></script>
<script src="{% static "js/gadjo.js" %}?{% start_timestamp %}"></script>
<script src="{% xstatic 'jquery' 'jquery.min.js' %}"></script>
<script src="{% xstatic 'jquery-ui' 'jquery-ui.min.js' %}"></script>
<script src="{% static "js/gadjo.js" %}?{% start_timestamp %}"></script>
{% endblock %}
{{ media }}
{% block extrascripts %}
{% endblock %}
</head>
<body data-gadjo="true" {% block bodyargs %}{% endblock %}>
<nav id="nav-skip" role="navigation" aria-label="{% trans "quick access" %}">
<ul>
<li><a href="#main-content">{% trans "Go to content" %}</a></li>
</ul>
</nav>
<div id="top">
{% block sidepage %}
<div id="top">
{% block sidepage %}
{% endblock %}
{% block user-links %}
<ul class="user-info">
{% if global_title %}
<li class="ui-platform-name">{{ global_title }}</li>
{% endif %}
{% if user.is_authenticated %}
<li class="ui-avatar">{% firstof request.session.mellon_session.avatar.0 user.get_full_name|slice:":1" %}</li>
<li class="ui-name">{{ user.get_full_name }}</li>
<li class="ui-logout"><a href="{% block logout-url %}index.html{% endblock %}"
title="{% trans "Logout" %}"></a></li>
{% endif %}
{% block help-link %}
{% endblock %}
{% block user-links %}
<ul class="user-info">
{% if global_title %}
<li class="ui-platform-name">{% if portal_url %}<a href="{{portal_url}}">{{ global_title }}</a>{% else %}{{ global_title }}{% endif %}</li>
{% endif %}
{% if user.is_authenticated %}
<li class="ui-avatar">{{ user.get_full_name|slice:":1" }}</li>
<li class="ui-name">{% block user-name %}{{ user.get_full_name }}{% endblock %}</li>
<li class="ui-logout"><a href="{% block logout-url %}index.html{% endblock %}"
title="{% trans "Logout" %}"><span class="sr-only">{% trans "Logout" %}</span></a></li>
{% endif %}
{% block help-link %}
{% endblock %}
</ul>
{% endblock %}
</div>
</ul>
{% endblock %}
</div>
<div id="header">
{% block site-header %}
<h1>{% block site-title %}{% endblock %}</h1>
{% block subheader %}{% endblock %}
{% endblock %}
</div>
<div id="main">
<div id="main">
<div id="main-content" {% block main-content-attributes %}{% endblock %}>
{% block main-content %}
<div id="more-user-links">
{% block more-user-links %}
<span id="breadcrumb">
{% block breadcrumb %}
<a href="{% block homepage-url %}/{% endblock %}">{% block homepage-title %}{% trans "Homepage" %}{% endblock %}</a>
{% endblock %}
</span>
{% endblock %}
</div>
<div id="content">
{% block old-ie-warning %}
<!--[if lt IE 9]>
<div class="old-ie-warning">
{% blocktrans %}
<p><strong>Do you know your web browser is obsolete?</strong> We recommend
you to <a href="http://windows.microsoft.com/en-us/internet-explorer/download-ie">update
your web browser</a> or to <a href="http://browsehappy.com/">use
different web browsers</a> as some features may not work.
{% endblocktrans %}
</div>
<![endif]-->
{% endblock %}
<div id="appbar">
{% block appbar %}
{% endblock %}
</div>
{% block messages %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}
{% block beforecontent %}
{% endblock %}
{% block content %}
{% endblock %}
<br style="clear: both;"/>
{% block aftercontent %}
{% endblock %}
</div> <!-- #content -->
<div id="main-content" {% block main-content-attributes %}{% endblock %}>
{% block main-content %}
<div id="more-user-links">
{% block more-user-links %}
<span id="breadcrumb">
{% block breadcrumb %}
<a href="{% block homepage-url %}/{% endblock %}">{% block homepage-title %}{% trans "Homepage" %}{% endblock %}</a>
{% endblock %}
</span>
{% endblock %}
</div> <!-- #main-content -->
</div>
<div id="content">
{% block after-main-content %}
<div id="appbar">
{% block appbar %}
{% endblock %}
</div>
{% block messages %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}
{% block beforecontent %}
{% endblock %}
{% block content %}
{% endblock %}
<br style="clear: both;"/>
{% block aftercontent %}
{% endblock %}
</div> <!-- #content -->
{% endblock %}
</div> <!-- #main-content -->
{% block sidebar %}
{% endblock %}
</div> <!-- #main -->
<div id="footer">
{% block footer %}
{% endblock %}
</div>
{% block page-end %}
{% block after-main-content %}
{% endblock %}
{% block sidebar %}
{% endblock %}
</div> <!-- #main -->
<div id="footer">
{% block footer %}
Copyright &copy; 2014 Entr'ouvert
{% endblock %}
</div>
{% block page-end %}
{% endblock %}
</body>
</html>

View File

@ -1,42 +0,0 @@
{% load gadjo i18n %}
<div class="{% block widget-css-classes %}widget
{{ field.css_classes }}
django-{{ field|field_class_name }}
{% if field.errors %}widget-with-error{% endif %}
{% if field.field.required %}widget-required{% else %}widget-optional{% endif %}{% endblock %}"
{% if field.id_for_label %}id="{{field.id_for_label}}_p"{% endif %}>
{% block widget-title %}
<div class="title" {% if field.id_for_label %}id="{{ field.id_for_label }}_title"{% endif %}>
{{ field.label_tag }}
{% if field.field.required %}
<span title="{% trans "This field is required." %}" class="required">*</span>
{% else %}
<span class="optional">{% trans "(optional)" %}</span>
{% endif %}
</div>
{% endblock %}
{% block widget-content %}
<div class="content"
{% if field.id_for_label %}aria-labelledby="{{ field.id_for_label }}_title"{% endif %}
{% block widget-attrs %}{% endblock %}>
{% block widget-hint %}
{% if field.help_text %}
<div class="hint" id="help_text_{{field.id_for_label}}"><p>{{ field.help_text|safe }}</p></div>
{% endif %}
{% endblock %}
{% block widget-control %}
{{ field }}
{% endblock %}
{% block widget-error %}
{% if field.errors %}
<div class="error" id="error_{{field.id_for_label}}"><p>
{% for error in field.errors %}
{{ error }}{% if not forloop.last %}<br>{% endif %}
{% endfor %}
</p></div>
{% endif %}
{% endblock %}
{% block widget-bottom %}{% endblock %}
</div>
{% endblock %}
</div>

View File

@ -1,17 +0,0 @@
{% load i18n %}
<div class="gadjo-multi-select-widget" data-row-id="{{ widget.name }}" data-row-label="{% trans "Value" %}">
<div class="gadjo-multi-select-widget--fields" role="group" aria-labelledby="{{ widget.name }}_title">
{% for widget in widget.subwidgets %}
<div class="gadjo-multi-select-widget--field">
<label for="{{ widget.name }}_{{ forloop.counter }}" class="sr-only">{% trans "Value" %} {{ forloop.counter }}</label>
<div class="gadjo-multi-select-widget--select-button-container">
{% include widget.template_name %}
<button type="button" name="{{ widget.name }}$remove_element" class="gadjo-multi-select-widget--button-remove" title="{% trans "Remove" %}" aria-label="{% trans "Remove value" %} {{ forloop.counter }}"></button>
</div>
</div>
{% endfor %}
</div>
<button type="button" name="{{ widget.name }}$add_element" class="gadjo-multi-select-widget--button-add" title="{% trans "Add" %}" aria-label="{% trans "Add" %}"></button>
</div>

View File

@ -1,27 +1,49 @@
from collections import OrderedDict
import re
import time
from collections import OrderedDict
from xstatic.main import XStatic
from django import template
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.forms import BoundField
from django.template import TemplateSyntaxError
from django.utils.html import escape
from django.utils.http import urlencode
register = template.Library()
@register.simple_tag
def xstatic(modname, filename):
try:
# list of tuples of the form (cdnname, protocol)
cdns = settings.CDNS
except AttributeError:
cdns = []
if settings.DEBUG:
filename = filename.replace('.min.', '.')
if cdns:
modname = str(modname.replace('-', '_'))
pkg = __import__('xstatic.pkg', fromlist=[modname])
mod = getattr(pkg, modname)
for cdnname, protocol in cdns:
try:
base_url = XStatic(mod, provider=cdnname, protocol=protocol).base_url
except KeyError:
continue
if isinstance(base_url, str):
# base_url is often a str
return base_url + '/' + filename
else:
# But it also can be a dict (which maps relative paths to
# full urls) (this happens with jquery CDN)
if filename in base_url:
return base_url.get(filename)
return settings.STATIC_URL + 'xstatic/' + filename
START_TIMESTAMP = time.strftime('%Y%m%d.%H%M')
START_TIMESTAMP = time.strftime('%Y%m%d.%H%M%S')
@register.simple_tag
def start_timestamp():
@ -29,8 +51,7 @@ def start_timestamp():
# {% querystring %} bits originally from django-tables2.
kwarg_re = re.compile(r'(?:(.+)=)?(.+)')
kwarg_re = re.compile(r"(?:(.+)=)?(.+)")
def token_kwargs(bits, parser):
"""
@ -52,10 +73,9 @@ def token_kwargs(bits, parser):
kwargs[parser.compile_filter(key)] = parser.compile_filter(value)
return kwargs
class QuerystringNode(template.Node):
def __init__(self, updates, removals):
super().__init__()
super(QuerystringNode, self).__init__()
self.updates = updates
self.removals = removals
@ -66,12 +86,11 @@ class QuerystringNode(template.Node):
for key, value in self.updates.items():
key = key.resolve(context)
value = value.resolve(context)
if key not in ('', None):
if key not in ("", None):
params[key] = value
for removal in self.removals:
params.pop(removal.resolve(context), None)
return escape('?' + urlencode(params, doseq=True))
return escape("?" + urlencode(params, doseq=True))
@register.tag
def querystring(parser, token):
@ -93,47 +112,7 @@ def querystring(parser, token):
updates = token_kwargs(bits, parser)
# ``bits`` should now be empty of a=b pairs, it should either be empty, or
# have ``without`` arguments.
if bits and bits.pop(0) != 'without':
if bits and bits.pop(0) != "without":
raise TemplateSyntaxError("Malformed arguments to '%s'" % tag)
removals = [parser.compile_filter(bit) for bit in bits]
return QuerystringNode(updates, removals)
@register.filter
def with_template(form):
form_template = template.loader.get_template('gadjo/form.html')
fields_with_templates = []
for field in form:
widget = field.field.widget
templates = ['gadjo/widget.html']
if hasattr(widget, 'input_type'):
templates.insert(0, 'gadjo/%s-widget.html' % widget.input_type)
aria_described_by = []
if field.field.help_text:
aria_described_by.append(f'help_text_{field.id_for_label}')
if field.errors:
aria_described_by.append(f'error_{field.id_for_label}')
field.field.widget.attrs['aria-invalid'] = 'true'
if field.field.required:
field.field.widget.attrs['aria-required'] = 'true'
if aria_described_by:
field.field.widget.attrs['aria-describedby'] = ' '.join(aria_described_by)
fields_with_templates.append(
(
field,
template.loader.select_template(templates),
)
)
return form_template.render({'form': form, 'fields_with_templates': fields_with_templates})
# pattern to transform Django camel case class names to CSS class names with
# dashes. (CheckboxInput -> checkbox-input)
class_name_pattern = re.compile(r'(?<!^)(?=[A-Z])')
@register.filter
def field_class_name(field):
if isinstance(field, BoundField):
field = field.field
return class_name_pattern.sub('-', field.widget.__class__.__name__).lower()

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
id="Calque_1"
data-name="Calque 1"
viewBox="0 0 63.95 65.06"
version="1.1"
sodipodi:docname="action-copy.svg"
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
inkscape:export-filename="/home/vdeniaud/src/gadjo/icons/action-copy.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<metadata
id="metadata25">
<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>Pictos_v3_EXPORT</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1916"
inkscape:window-height="1041"
id="namedview23"
showgrid="false"
inkscape:zoom="6.611114"
inkscape:cx="10.36951"
inkscape:cy="38.426559"
inkscape:window-x="0"
inkscape:window-y="37"
inkscape:window-maximized="0"
inkscape:current-layer="Calque_1"
inkscape:document-rotation="0"
inkscape:snap-global="true" />
<defs
id="defs4">
<style
id="style2">.cls-1 { fill:#242d3c; }
</style>
</defs>
<title
id="title6">Pictos_v3_EXPORT</title>
<g
id="g113">
<path
id="path105"
d="m 53.470703,53.541016 h -2.230469 v 6.748046 c 4.4e-4,1.40513 -1.135894,2.545831 -2.541015,2.550782 H 4.7695312 C 3.3613573,62.839197 2.2202711,61.697236 2.2207031,60.289062 V 16.369141 C 2.2213493,14.96173 3.3621199,13.820959 4.7695312,13.820312 H 10.544922 V 11.589844 H 4.7695312 C 2.1339737,11.595616 3.8129446e-4,13.733577 0,16.369141 v 43.919921 c 0.00468321,2.632514 2.1370196,4.765724 4.7695312,4.771485 H 48.699219 c 2.633274,-0.0047 4.766797,-2.138211 4.771484,-4.771485 z M 10.544922,13.820312 h 38.154297 c 1.404359,0.0049 2.540379,1.144461 2.541015,2.548829 v 37.171875 h 2.230469 V 16.369141 c -3.84e-4,-2.636325 -2.135164,-4.7746 -4.771484,-4.779297 H 10.544922 Z"
class="cls-1"
style="" />
</g>
<path
d="m 15.316406,0.07226562 c -2.63632,0.0046968 -4.7711,2.14297238 -4.771484,4.77929688 v 6.7382815 h 2.220703 V 4.8515625 C 12.765193,3.4426262 13.90747,2.3003496 15.316406,2.3007812 h 43.929688 c 1.404358,0.00602 2.539505,1.1464109 2.539062,2.5507813 V 48.771484 c 4.44e-4,1.404371 -1.134704,2.544758 -2.539062,2.550782 h -5.775391 v 2.21875 h 5.775391 c 2.631751,-0.0058 4.763774,-2.137781 4.769531,-4.769532 V 4.8515625 C 64.015244,2.2159989 61.881651,0.07803792 59.246094,0.07226562 Z"
id="path8"
class="cls-1"
style="" />
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -1 +0,0 @@
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 53.63 53.22"><defs><style>.cls-1{fill:#242d3c;}</style></defs><title>Pictos_v3_EXPORT</title><path class="cls-1" d="M48.71,53.22h0L4.75,53a5.35,5.35,0,0,1-3.26-1.06A3.67,3.67,0,0,1,0,49.06L.16,9.4A3.66,3.66,0,0,1,1.68,6.54a5.37,5.37,0,0,1,3.25-1H5l43.93.22a5.35,5.35,0,0,1,3.26,1.06,3.65,3.65,0,0,1,1.49,2.88l-.16,39.66h0A3.66,3.66,0,0,1,52,52.18,5.36,5.36,0,0,1,48.71,53.22ZM4.93,7.73A3.2,3.2,0,0,0,3,8.31a1.47,1.47,0,0,0-.64,1.1L2.22,49.07a1.49,1.49,0,0,0,.63,1.11,3.17,3.17,0,0,0,1.91.6L48.69,51h0a3.19,3.19,0,0,0,1.89-.58,1.45,1.45,0,0,0,.64-1.1l.17-39.66a1.51,1.51,0,0,0-.63-1.11,3.17,3.17,0,0,0-1.91-.6L4.94,7.73ZM52.36,49.32h0Z"/><path class="cls-1" d="M14.47,15A2.5,2.5,0,0,1,12,12.5V2.5a2.5,2.5,0,1,1,5,0v10A2.5,2.5,0,0,1,14.47,15Z"/><path class="cls-1" d="M39.47,15A2.5,2.5,0,0,1,37,12.5V2.5a2.5,2.5,0,0,1,5,0v10A2.5,2.5,0,0,1,39.47,15Z"/><rect class="cls-1" x="1.47" y="21" width="50.5" height="3"/><path class="cls-1" d="M22.67,43.83,20.46,40.7l-1.84,3.13h-4.3l4-6.2-4.13-5.84h4.47l2.13,3,1.77-3h4.3l-3.9,6.09,4.22,5.95Z"/><path class="cls-1" d="M35.32,43.83,33.11,40.7l-1.84,3.13H27l4-6.2L26.8,31.79h4.47l2.13,3,1.77-3h4.3l-3.9,6.09,4.22,5.95Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,18 +0,0 @@
<svg data-name="Calque 1" version="1.1" viewBox="0 0 53.63 53.22" xmlns="http://www.w3.org/2000/svg">
<defs>
<style>.cls-1{fill:#242d3c;}</style>
</defs>
<title>Pictos_v3_EXPORT</title>
<g transform="translate(0 -7.3085)">
<path class="cls-1" d="m48.71 53.22-43.96-0.22c-1.1735 0.013794-2.319-0.35867-3.26-1.06-0.91683-0.67663-1.4674-1.7407-1.49-2.88l0.16-30.583c0.034329-1.1378 0.59614-2.1949 1.52-2.86 0.94641-0.67658 2.0869-1.0275 3.25-1h0.07l43.93 0.22c1.1735-0.01379 2.319 0.35867 3.26 1.06 0.91924 0.67458 1.4704 1.74 1.49 2.88l-0.16 30.583c-0.04653 1.1236-0.60701 2.1634-1.52 2.82-0.95206 0.69982-2.1087 1.0654-3.29 1.04zm-43.78-36.413c-0.68901-0.01957-1.3659 0.18385-1.93 0.58-0.36922 0.25053-0.60467 0.6552-0.64 1.1l-0.14 30.583c0.032879 0.44577 0.26414 0.85322 0.63 1.11 0.55514 0.40107 1.2252 0.61157 1.91 0.6l43.93 0.22c0.67552 0.01169 1.3373-0.1914 1.89-0.58 0.37144-0.24846 0.60757-0.6543 0.64-1.1l0.17-30.583c-0.03562-0.44493-0.26626-0.8513-0.63-1.11-0.55514-0.40107-1.2252-0.61157-1.91-0.6l-43.91-0.22z"/>
<rect class="cls-1" x="1.47" y="24.096" width="50.578" height="6.9463"/>
<g fill="#242d3c">
<path class="cls-1" d="m7.3244 45.502-0.44817-0.63474-0.37314 0.63474h-0.872l0.81116-1.2573-0.83753-1.1843h0.90648l0.43195 0.60837 0.35894-0.60837h0.872l-0.79089 1.235 0.85578 1.2066z"/>
<path class="cls-1" d="m9.8897 45.502-0.44817-0.63474-0.37314 0.63474h-0.86592l0.81117-1.2573-0.85172-1.1843h0.90648l0.43195 0.60837 0.35894-0.60837h0.872l-0.79089 1.235 0.85578 1.2066z"/>
<path class="cls-1" d="m14.952 45.509-0.44817-0.63474-0.37314 0.63474h-0.872l0.81116-1.2573-0.83753-1.1843h0.90648l0.43195 0.60837 0.35894-0.60837h0.872l-0.79089 1.235 0.85578 1.2066z"/>
<path class="cls-1" d="m17.517 45.509-0.44817-0.63474-0.37314 0.63474h-0.86592l0.81117-1.2573-0.85172-1.1843h0.90648l0.43195 0.60837 0.35894-0.60837h0.872l-0.79089 1.235 0.85578 1.2066z"/>
<path class="cls-1" d="m20.117 45.509-0.44817-0.63474-0.37314 0.63474h-0.872l0.81116-1.2573-0.83753-1.1843h0.90648l0.43195 0.60837 0.35894-0.60837h0.872l-0.79089 1.235 0.85578 1.2066z"/>
<path class="cls-1" d="m22.682 45.509-0.44817-0.63474-0.37314 0.63474h-0.86592l0.81117-1.2573-0.85172-1.1843h0.90648l0.43195 0.60837 0.35894-0.60837h0.872l-0.79089 1.235 0.85578 1.2066z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1 +0,0 @@
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 53.5 44.15"><defs><style>.cls-1{fill:#242d3c;}</style></defs><title>Pictos_v3_EXPORT</title><path class="cls-1" d="M44.44,44.15H1.5A1.5,1.5,0,0,1,0,42.65V12.51A1.5,1.5,0,0,1,1.5,11H44.44a1.5,1.5,0,0,1,1.5,1.5V42.65A1.5,1.5,0,0,1,44.44,44.15ZM3,41.15H42.94V14H3Z"/><path class="cls-1" d="M52,38.59a1.5,1.5,0,0,1-1.5-1.5V3H24.13V6a1.5,1.5,0,0,1-1.5,1.5H4.84a1.5,1.5,0,0,1,0-3H21.13V1.5A1.5,1.5,0,0,1,22.63,0H52a1.5,1.5,0,0,1,1.5,1.5V37.09A1.5,1.5,0,0,1,52,38.59Z"/></svg>

Before

Width:  |  Height:  |  Size: 557 B

View File

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 53.5 44.15">
<defs><style>.cls-1{fill:#242d3c;}</style></defs>
<path d="M 44.44,44.15 H 1.5 C 0.67157288,44.15 0,43.478427 0,42.65 V 12.51 C -0.00554899,11.67767 0.66765187,10.999982 1.5,11 h 42.94 c 0.828427,0 1.5,0.671573 1.5,1.5 v 30.15 c 0,0.828427 -0.671573,1.5 -1.5,1.5 z" class="cls-1" />
<path d="M52,38.59a1.5,1.5,0,0,1-1.5-1.5V3H24.13V6a1.5,1.5,0,0,1-1.5,1.5H4.84a1.5,1.5,0,0,1,0-3H21.13V1.5A1.5,1.5,0,0,1,22.63,0H52a1.5,1.5,0,0,1,1.5,1.5V37.09A1.5,1.5,0,0,1,52,38.59Z" class="cls-1" />
</svg>

Before

Width:  |  Height:  |  Size: 563 B

View File

@ -1 +0,0 @@
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 63.72 64.25" style="enable-background:new 0 0 63.72 64.25;" xml:space="preserve"><defs><style type="text/css">.st0{fill:#242d3c;}</style></defs><g><circle class="st0" cx="32.36" cy="8.36" r="8.36"/><path class="st0" d="M47.97,32.75H46v-0.71c0-7.53-6.11-13.64-13.64-13.64s-13.64,6.11-13.64,13.64v0.71h-2.97 C7.07,32.75,0,39.82,0,48.5s7.07,15.75,15.75,15.75h32.22c8.68,0,15.75-7.07,15.75-15.75S56.66,32.75,47.97,32.75z M47.97,61.75 H15.75C8.44,61.75,2.5,55.81,2.5,48.5s5.94-13.25,13.25-13.25h32.22c7.31,0,13.25,5.94,13.25,13.25S55.28,61.75,47.97,61.75z"/><ellipse transform="matrix(0.7071 -0.7071 0.7071 0.7071 -20.4798 47.5573)" class="st0" cx="47.17" cy="48.5" rx="9.26" ry="9.26"/></g></svg>

Before

Width:  |  Height:  |  Size: 833 B

View File

@ -1 +0,0 @@
bankcard.svg

View File

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
width="4.5155554mm"
height="4.5155559mm"
viewBox="0 0 15.999999 16.000001"
id="svg6439"
version="1.1"
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
sodipodi:docname="jump.svg">
<defs
id="defs6441" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="19.485951"
inkscape:cx="15.20953"
inkscape:cy="12.040142"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1600"
inkscape:window-height="836"
inkscape:window-x="179"
inkscape:window-y="1107"
inkscape:window-maximized="1"
inkscape:document-rotation="0" />
<metadata
id="metadata6444">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(499.42858,-850.07649)">
<g
id="g7122"
transform="translate(0.98417231,-1.968743)">
<circle
r="2.96875"
cy="863.04523"
cx="-496.42838"
id="path24876-5"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new"
d="m -492.20601,862.09968 4.64422,-4.60121 1.13341,1.69492 1,-5.1169 -4.81381,0.19547 1.27128,1.56728 -5.38712,3.34623 c 1.4866,0.41967 1.93493,0.85933 2.15202,2.91421 z"
id="path24884-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc"
inkscape:transform-center-x="-3.9656263"
inkscape:transform-center-y="-5.5812618" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -1,88 +0,0 @@
<?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"
sodipodi:docname="studio.svg"
height="16"
id="svg7384"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
version="1.1"
width="16.53125">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1600"
inkscape:window-height="836"
id="namedview11"
showgrid="false"
inkscape:zoom="61"
inkscape:cx="7.6721976"
inkscape:cy="5.7312166"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="layer10" />
<metadata
id="metadata90">
<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>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<defs
id="defs7386" />
<g
inkscape:groupmode="layer"
id="layer9"
inkscape:label="status"
style="display:inline"
transform="translate(-260.7502,-467)" />
<g
inkscape:groupmode="layer"
id="layer10"
inkscape:label="devices"
transform="translate(-260.7502,-467)">
<path
inkscape:connector-curvature="0"
d="m 269.0021,467.00379 -1.0019,0.0275 0.0312,0.5 c 0.0471,0.46556 -0.20254,0.96951 -0.59375,1.21875 -0.35305,0.24895 -0.90493,0.1983 -1.59375,0.21875 -0.34855,0.003 -0.70297,0.0839 -1.03125,0.28125 -0.32828,0.19733 -0.64985,0.5469 -0.71875,1 -0.15832,0.89239 0.45382,1.63343 1.15625,1.78125 0.80729,0.17604 1.64453,0.0756 2.625,0 0.25579,-0.0197 0.60056,0.0205 0.8125,0.125 0.33374,0.26075 0.28443,0.40291 0.28125,0.875 h -4.90625 -0.75 l -0.21875,0.71875 -1.96875,7 -0.375,1.28125 h 1.34375 13.875 1.3125 l -0.375,-1.28125 -1.90625,-6.8125 -0.88915,1.31458 1.68141,5.84563 h -13.62282 l 2.04028,-6.97063 c 2.35142,-0.0858 3.41529,0.0611 5.22773,-0.002 l 0.53125,-1.0625 v -0.0312 -0.46875 c -0.003,-0.61146 -0.40574,-1.09656 -0.84375,-1.3125 -0.43801,-0.21594 -0.93011,-0.25063 -1.34375,-0.21875 -0.99591,0.0768 -1.73951,0.12494 -2.3125,0 h -0.0312 c -0.19949,-0.042 -0.41743,-0.20971 -0.34375,-0.625 0.0189,-0.12428 0.0777,-0.19648 0.21875,-0.28125 0.14101,-0.0848 0.35246,-0.15487 0.53125,-0.15625 h 0.0312 c 0.56397,-0.0167 1.37705,0.11764 2.09375,-0.40625 0.81874,-0.59848 1.15373,-1.39515 1.0625,-2.125 z"
id="path8540"
sodipodi:nodetypes="cccccccccccccccccccccccccccccscccccccssc"
style="color:#ff0000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:Sans;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;enable-background:new" />
<path
inkscape:connector-curvature="0"
d="m 274.12612,469.07046 c 0,0 -2.51922,3.50643 -4.04033,5.96897 l -1.40567,1.1673 0.0373,1.57392 -0.76313,1.24524 0.69536,-10e-4 0.74028,-0.58334 1.67496,-0.4626 0.5949,-1.48097 4.18505,-6.36462 z"
id="path8552"
sodipodi:nodetypes="ccccccccccc"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#ff0000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;font-family:Sans;-inkscape-font-specification:Sans" />
<path
sodipodi:cx="34.073708"
sodipodi:cy="252.43883"
d="m 34.648232,252.43883 a 0.57452428,0.57452428 0 1 1 -1.149049,0 0.57452428,0.57452428 0 1 1 1.149049,0 z"
id="path8566"
sodipodi:rx="0.57452428"
sodipodi:ry="0.57452428"
style="color:#ff0000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
transform="matrix(1.1306064,0,0,1.1306064,236.54995,184.02987)"
sodipodi:type="arc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,17 +0,0 @@
#! /usr/bin/env python3
# inkscape wrapper to support command-line parameters for <1.0 and 1.0
# versions.
import subprocess
import sys
inkscape_version = subprocess.check_output('inkscape --version', shell=True)
args = sys.argv[1:]
if b'Inkscape 0' not in inkscape_version:
# --export-png replaced by --export-filename
# --without-gui and --file removed
args = [
x.replace('--export-png', '--export-filename') for x in args if x not in ('--without-gui', '--file')
]
sys.exit(subprocess.call(['inkscape'] + args))

115
pylint.rc
View File

@ -1,115 +0,0 @@
[MASTER]
persistent=yes
ignore=vendor,Bouncers,ezt.py
[MESSAGES CONTROL]
disable=
abstract-method,
arguments-differ,
attribute-defined-outside-init,
bad-super-call,
consider-using-f-string,
consider-using-set-comprehension,
consider-using-ternary,
cyclic-import,
duplicate-code,
exec-used,
fixme,
import-outside-toplevel,
inconsistent-return-statements,
invalid-name,
invalid-str-returned,
keyword-arg-before-vararg,
missing-class-docstring,
missing-function-docstring,
missing-module-docstring,
no-else-return,
no-member,
not-an-iterable,
protected-access,
raise-missing-from,
redefined-argument-from-local,
redefined-builtin,
redefined-outer-name,
superfluous-parens,
too-many-ancestors,
too-many-branches,
too-many-instance-attributes,
too-many-lines,
too-many-locals,
too-many-nested-blocks,
too-many-return-statements,
too-many-statements,
undefined-loop-variable,
unnecessary-lambda-assignment,
unspecified-encoding,
unsubscriptable-object,
unsupported-assignment-operation,
unsupported-membership-test,
unused-argument,
use-a-generator,
use-implicit-booleaness-not-comparison
[REPORTS]
output-format=parseable
[BASIC]
no-docstring-rgx=__.*__|_.*
class-rgx=[A-Z_][a-zA-Z0-9_]+$
function-rgx=[a-zA_][a-zA-Z0-9_]{2,70}$
method-rgx=[a-z_][a-zA-Z0-9_]{2,70}$
const-rgx=(([A-Z_][A-Z0-9_]*)|([a-z_][a-z0-9_]*)|(__.*__)|register|urlpatterns)$
good-names=_,i,j,k,e,x,Run,,setUp,tearDown,r,p,s,v,fd
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set).
ignored-classes=SQLObject,WSGIRequest,Publisher,NullSessionManager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed.
generated-members=objects,DoesNotExist,id,pk,_meta,base_fields,context
# List of method names used to declare (i.e. assign) instance attributes
defining-attr-methods=__init__,__new__,setUp
[VARIABLES]
init-import=no
dummy-variables-rgx=_|dummy
additional-builtins=_,N_,ngettext
good-names=_,i,j,k,e,x,Run,,setUp,tearDown,r,p,s,v,fd
[SIMILARITIES]
min-similarity-lines=6
ignore-comments=yes
ignore-docstrings=yes
[MISCELLANEOUS]
notes=FIXME,XXX,TODO
[FORMAT]
max-line-length=160
max-module-lines=2000
indent-string=' '
[DESIGN]
max-args=10
max-locals=15
max-returns=6
max-branches=12
max-statements=50
max-parents=7
max-attributes=7
min-public-methods=0
max-public-methods=50

View File

@ -1,5 +0,0 @@
#! /bin/bash
set -e -x
env
pylint -f parseable --rcfile pylint.rc "$@" | tee pylint.out || /bin/true

View File

@ -1,2 +0,0 @@
[pytest]
DJANGO_SETTINGS_MODULE = tests.project.settings

121
setup.py
View File

@ -1,27 +1,26 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import glob
import os
import glob
import re
import subprocess
import sys
import subprocess
import tempfile
import xml.etree.ElementTree as ET
from distutils.cmd import Command
from distutils.command.build import build as _build
from distutils.command.sdist import sdist
from distutils.errors import CompileError
from distutils.spawn import find_executable
from setuptools import find_packages, setup
from setuptools.command.install_lib import install_lib as _install_lib
inkscape = os.path.abspath(os.path.join(os.path.dirname(__file__), 'inkscape_wrapper.py'))
from distutils.command.build import build as _build
from distutils.command.sdist import sdist
from setuptools import setup, find_packages
class eo_sdist(sdist):
def run(self):
print('creating VERSION file')
print("creating VERSION file")
if os.path.exists('VERSION'):
os.remove('VERSION')
version = get_version()
@ -29,35 +28,33 @@ class eo_sdist(sdist):
version_file.write(version)
version_file.close()
sdist.run(self)
print('removing VERSION file')
print("removing VERSION file")
if os.path.exists('VERSION'):
os.remove('VERSION')
def get_version():
'''Use the VERSION, if absent generates a version with git describe, if not
tag exists, take 0.0- and add the length of the commit log.
tag exists, take 0.0- and add the length of the commit log.
'''
if os.path.exists('VERSION'):
with open('VERSION') as v:
with open('VERSION', 'r') as v:
return v.read()
if os.path.exists('.git'):
p = subprocess.Popen(
['git', 'describe', '--dirty=.dirty', '--match=v*'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
p = subprocess.Popen(['git','describe','--dirty=.dirty','--match=v*'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result = p.communicate()[0]
if p.returncode == 0:
result = result.decode('ascii').strip()[1:] # strip spaces/newlines and initial v
if '-' in result: # not a tagged version
result = result.decode('ascii').strip()[1:] # strip spaces/newlines and initial v
if '-' in result: # not a tagged version
real_number, commit_count, commit_hash = result.split('-', 2)
version = '%s.post%s+%s' % (real_number, commit_count, commit_hash)
else:
version = result.replace('.dirty', '+dirty')
version = result
return version
else:
return '0.0.post%s' % len(subprocess.check_output(['git', 'rev-list', 'HEAD']).splitlines())
return '0.0.post%s' % len(
subprocess.check_output(
['git', 'rev-list', 'HEAD']).splitlines())
return '0.0'
@ -75,7 +72,6 @@ class compile_translations(Command):
curdir = os.getcwd()
try:
from django.core.management import call_command
for path, dirs, files in os.walk('gadjo'):
if 'locale' not in dirs:
continue
@ -100,14 +96,12 @@ class compile_scss(Command):
def run(self):
sass_bin = None
for program in ('sassc', 'sass'):
for program in ('sass', 'sassc'):
sass_bin = find_executable(program)
if sass_bin:
break
if not sass_bin:
raise CompileError(
'A sass compiler is required but none was found. See sass-lang.com for choices.'
)
raise CompileError('A sass compiler is required but none was found. See sass-lang.com for choices.')
for package in self.distribution.packages:
for package_path in __import__(package).__path__:
@ -117,14 +111,10 @@ class compile_scss(Command):
continue
if filename.startswith('_'):
continue
subprocess.check_call(
[
sass_bin,
'%s/%s' % (path, filename),
'%s/%s' % (path, filename.replace('.scss', '.css')),
],
env={'LC_ALL': 'C.UTF-8'},
)
subprocess.check_call([sass_bin, '%s/%s' % (path, filename),
'%s/%s' % (path, filename.replace('.scss', '.css'))],
env={'LC_ALL': 'C.UTF-8'}
)
class build_icons(Command):
@ -142,34 +132,38 @@ class build_icons(Command):
if not os.path.exists(destpath):
os.mkdir(destpath)
variants_applications = {
'small': {'colour': '386ede', 'width': '40'},
'small': {'colour': 'e7e7e7', 'width': '20'},
'small.white': {'colour': 'ffffff', 'width': '20'},
'small.386ede': {'colour': '386ede', 'width': '20'},
'small.ff375e': {'colour': 'ff375e', 'width': '20'},
'small.6f2b92': {'colour': '6f2b92', 'width': '20'},
'large': {'colour': 'e7e7e7', 'width': '80'},
'large-hover': {'colour': 'bebebe', 'width': '80'},
}
variants_actions = {
'small': {'colour': '386ede', 'width': '40'},
'small.white': {'colour': 'ffffff', 'width': '40'},
'hover': {'colour': '2b2b2b', 'width': '40'},
'small.386ede': {'colour': '386ede', 'width': '20'},
'small.ff375e': {'colour': 'ff375e', 'width': '20'},
'small.6f2b92': {'colour': '6f2b92', 'width': '20'},
'hover': {'colour': '2b2b2b', 'width': '20'},
}
for basepath, dirnames, filenames in os.walk('icons'):
for filename in filenames:
basename = os.path.splitext(filename)[0]
variants = variants_applications
if not filename.endswith('.svg'):
continue
if filename.startswith('action-'):
variants = variants_actions
for variant in variants:
dest_filename = '%s.%s.png' % (basename, variant)
destname = os.path.join(destpath, dest_filename)
self.generate(os.path.join(basepath, filename), destname, **variants.get(variant))
self.generate(os.path.join(basepath, filename), destname,
**variants.get(variant))
def generate(self, src, dest, colour, width, **kwargs):
if os.path.exists(dest) and os.stat(dest).st_mtime >= os.stat(src).st_mtime:
return
# default values
from PIL import Image, PngImagePlugin
from PIL import Image
from PIL import PngImagePlugin
license = 'Creative Commons Attribution-Share Alike 3.0'
if 'old-set' in src:
author = 'GNOME Project'
@ -187,20 +181,12 @@ class build_icons(Command):
f.write(ET.tostring(tree))
f.close()
subprocess.call(
[
inkscape,
'--without-gui',
'--file',
f.name,
'--export-area-drawing',
'--export-area-snap',
'--export-png',
dest,
'--export-width',
width,
]
)
subprocess.call(['inkscape', '--without-gui',
'--file', f.name,
'--export-area-drawing',
'--export-area-snap',
'--export-png', dest,
'--export-width', width])
# write down licensing info in the png file
meta = PngImagePlugin.PngInfo()
@ -210,11 +196,9 @@ class build_icons(Command):
class build(_build):
sub_commands = [
('compile_translations', None),
('compile_scss', None),
('build_icons', None),
] + _build.sub_commands
sub_commands = [('compile_translations', None),
('compile_scss', None),
('build_icons', None)] + _build.sub_commands
class install_lib(_install_lib):
@ -222,12 +206,12 @@ class install_lib(_install_lib):
self.run_command('compile_translations')
_install_lib.run(self)
setup(
name='gadjo',
version=get_version(),
license='AGPLv3 or later',
description='Django base template tailored for management interfaces',
long_description=open(os.path.join(os.path.dirname(__file__), 'README.txt')).read(),
url='https://dev.entrouvert.org/projects/gadjo/',
author='Frederic Peters',
author_email='fpeters@entrouvert.com',
@ -235,11 +219,11 @@ setup(
include_package_data=True,
install_requires=[
'XStatic',
'XStatic_Font_Awesome<5',
'XStatic_Font_Awesome',
'XStatic_jQuery',
'XStatic_jquery_ui',
'XStatic_OpenSans',
],
],
setup_requires=[
'Pillow',
],
@ -251,6 +235,7 @@ setup(
'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
],
zip_safe=False,
@ -260,6 +245,6 @@ setup(
'compile_scss': compile_scss,
'compile_translations': compile_translations,
'install_lib': install_lib,
'sdist': eo_sdist,
'sdist': eo_sdist
},
)

View File

View File

@ -1,10 +0,0 @@
import pytest
@pytest.fixture
def nocache(settings):
settings.CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}

View File

@ -1,37 +0,0 @@
import os
DATABASES = {
'default': {
'ENGINE': os.environ.get('DB_ENGINE', 'django.db.backends.postgresql_psycopg2'),
'NAME': 'gadjo-test-%s' % os.environ.get('BRANCH_NAME', '').replace('/', '-')[:45],
}
}
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [],
'builtins': [
'gadjo.templatetags.gadjo',
],
},
},
]
DEBUG = True
USE_TZ = True
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sites',
'gadjo',
]
STATIC_URL = '/static/'
SITE_ID = 1
MIDDLEWARE_CLASSES = ()
LOGGING = {}
SECRET_KEY = 'yay'

View File

@ -1,6 +0,0 @@
import gadjo.finders
def test_finder():
finder = gadjo.finders.XStaticFinder()
assert len(finder.find(path='', all=True)) == 4

View File

@ -1,81 +0,0 @@
import html
import urllib
from django import forms
from django.template import Context, Template
from django.test.client import RequestFactory
from pyquery import PyQuery
def test_start_timestamp():
t = Template('{% start_timestamp %}')
assert t.render(Context())
def test_querystring():
t = Template('{% querystring "name"="Ayers" "age"=20 %}')
ctx = Context({'request': RequestFactory().get('/')})
assert urllib.parse.parse_qs(urllib.parse.urlparse(html.unescape(t.render(ctx))).query) == {
'age': ['20'],
'name': ['Ayers'],
}
ctx = Context({'request': RequestFactory().get('/?age=10')})
assert urllib.parse.parse_qs(urllib.parse.urlparse(html.unescape(t.render(ctx))).query) == {
'age': ['20'],
'name': ['Ayers'],
}
t = Template('{% querystring "name"="Ayers" without "gender" %}')
ctx = Context({'request': RequestFactory().get('/')})
assert urllib.parse.parse_qs(urllib.parse.urlparse(html.unescape(t.render(ctx))).query) == {
'name': ['Ayers']
}
ctx = Context({'request': RequestFactory().get('/?gender=male')})
assert urllib.parse.parse_qs(urllib.parse.urlparse(html.unescape(t.render(ctx))).query) == {
'name': ['Ayers']
}
def test_with_template():
class ExampleForm(forms.Form):
text = forms.CharField(label='Text', max_length=50)
request = RequestFactory().get('/')
t = Template('{{ form|with_template }}')
ctx = Context({'request': request, 'form': ExampleForm()})
rendered = t.render(ctx)
assert PyQuery(rendered).find('input[type=text]')
assert not PyQuery(rendered).find('input[type=text]').attr['aria-invalid']
assert PyQuery(rendered).find('input[type=text]').attr['aria-required']
ctx = Context({'request': request, 'form': ExampleForm(data=request.GET)})
rendered = t.render(ctx)
assert (
PyQuery(rendered).find('input[type=text][aria-describedby]').attr['aria-describedby']
== 'error_id_text'
)
assert PyQuery(rendered).find('input[type=text]').attr['aria-invalid']
class ExampleForm(forms.Form):
text = forms.CharField(label='Text', max_length=50, help_text='Help text')
ctx = Context({'request': request, 'form': ExampleForm()})
rendered = t.render(ctx)
assert (
PyQuery(rendered).find('input[type=text][aria-describedby]').attr['aria-describedby']
== 'help_text_id_text'
)
ctx = Context({'request': request, 'form': ExampleForm(data=request.GET)})
rendered = t.render(ctx)
assert (
PyQuery(rendered).find('input[type=text][aria-describedby]').attr['aria-describedby']
== 'help_text_id_text error_id_text'
)
class ExampleForm(forms.Form):
text = forms.CharField(label='Text', max_length=50, required=False)
ctx = Context({'request': request, 'form': ExampleForm(data=request.GET)})
rendered = t.render(ctx)
assert not PyQuery(rendered).find('input[type=text]').attr['aria-required']

View File

@ -1,51 +0,0 @@
from django import forms
from django.template import Context, Template
from django.test.client import RequestFactory
from pyquery import PyQuery
from gadjo.forms.widgets import MultiSelectWidget
def test_multiselect_widget():
class ExampleForm(forms.Form):
choices = forms.MultipleChoiceField(
label='choices', choices=[('a', 'Aa'), ('b', 'Bb'), ('c', 'Cc')], widget=MultiSelectWidget
)
request = RequestFactory().get('/')
t = Template('{{ form|with_template }}')
ctx = Context({'request': request, 'form': ExampleForm()})
rendered = t.render(ctx)
assert len(PyQuery(rendered).find('select')) == 1
assert PyQuery(rendered).find('.gadjo-multi-select-widget--button-add')
request = RequestFactory().get('/?choices=a&choices=b')
t = Template('{{ form|with_template }}')
ctx = Context({'request': request, 'form': ExampleForm(data=request.GET)})
rendered = t.render(ctx)
assert len(PyQuery(rendered).find('select')) == 2
assert PyQuery(rendered).find('option[selected]').text() == 'Aa Bb'
assert ctx['form'].cleaned_data == {'choices': ['a', 'b']}
def test_multiselect_widget_omitted_from_data():
class ExampleForm(forms.Form):
choices = forms.MultipleChoiceField(
label='choices', choices=[('a', 'Aa'), ('b', 'Bb'), ('c', 'Cc')], widget=MultiSelectWidget
)
form = ExampleForm(data={})
assert (
form.fields['choices'].widget.value_omitted_from_data(
form.data, form.files, form.add_prefix('choices')
)
is True
)
form = ExampleForm(data={'choices': 'a'})
assert (
form.fields['choices'].widget.value_omitted_from_data(
form.data, form.files, form.add_prefix('choices')
)
is False
)

31
tox.ini
View File

@ -1,31 +0,0 @@
[tox]
envlist = codestyle-coverage-pylint
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/gadjo/{env:BRANCH_NAME:}
[testenv]
usedevelop =
coverage: True
nocoverage: False
setenv =
SETUPTOOLS_USE_DISTUTILS=stdlib
JUNIT=--junitxml=junit-{envname}.xml
coverage: COVERAGE=--cov-report xml --cov-report html --cov=gadjo/
deps =
pytest
pytest-django
WebTest
psycopg2-binary
psycopg2
pyquery
codestyle: pre-commit
coverage: pytest-cov
pylint: pylint<3
pylint: astroid<3
pylint: pylint-django
pylint: django>=3.2,<3.3
allowlist_externals =
./pylint.sh
commands =
pytest {posargs: {env:JUNIT:} {env:COVERAGE:} tests/}
codestyle: pre-commit run --all-files --show-diff-on-failure
pylint: ./pylint.sh gadjo/