Merge branch 'upgrade-sf3' into edit-user-password

This commit is contained in:
2018-08-16 11:31:07 +02:00
99 changed files with 2929 additions and 497 deletions

View File

@@ -1,6 +1,9 @@
Chill\MainBundle\Entity\PostalCode:
type: entity
table: chill_main_postal_code
repositoryClass: Chill\MainBundle\Repository\PostalCodeRepository
indexes:
- { name: search_name_code, columns: [ "code", "label" ] }
id:
id:
type: integer

View File

@@ -14,6 +14,21 @@ Chill\MainBundle\Entity\User:
username:
type: string
length: 80
usernameCanonical:
name: username_canonical
type: string
length: 80
unique: true
email:
type: string
length: 150
nullable: true
emailCanonical:
name: email_canonical
type: string
length: 150
nullable: true
unique: true
password:
type: string
length: 255

View File

@@ -17,6 +17,10 @@ chill_main_admin:
chill_main_exports:
resource: "@ChillMainBundle/Resources/config/routing/exports.yml"
prefix: "{_locale}/exports"
chill_postal_code:
resource: "@ChillMainBundle/Resources/config/routing/postal-code.yml"
prefix: "{_locale}/postal-code"
root:
path: /
@@ -32,12 +36,6 @@ chill_main_homepage_without_locale:
chill_main_homepage:
path: /{_locale}/homepage
defaults: { _controller: ChillMainBundle:Default:index }
options:
menus:
section:
order: 10
label: Homepage
icons: [home]
chill_main_admin_central:
@@ -80,13 +78,7 @@ login_check:
logout:
path: /logout
options:
menus:
user:
order: 10
label: Logout
icon: power-off
password:
path: /password
defaults: { _controller: ChillMainBundle:Password:userPassword }
defaults: { _controller: ChillMainBundle:Password:userPassword }

View File

@@ -1,12 +1,6 @@
chill_main_export_index:
path: /
defaults: { _controller: ChillMainBundle:Export:index }
options:
menus:
section:
order: 20
label: Export Menu
icons: [upload]
chill_main_export_new:
path: /new/{alias}

View File

@@ -0,0 +1,4 @@
chill_main_postal_code_search:
path: /search
defaults: { _controller: ChillMainBundle:PostalCode:search }

View File

@@ -2,27 +2,6 @@ parameters:
# cl_chill_main.example.class: Chill\MainBundle\Example
services:
chill.main.routes_loader:
class: Chill\MainBundle\Routing\Loader\ChillRoutesLoader
arguments:
- "%chill_main.routing.resources%"
tags:
- { name: routing.loader }
chill.main.menu_composer:
class: Chill\MainBundle\Routing\MenuComposer
#must be set in function to avoid circular reference with chill.main.twig.chill_menu
calls:
- [setContainer, ["@service_container"]]
chill.main.twig.chill_menu:
class: Chill\MainBundle\Routing\MenuTwig
arguments:
- "@chill.main.menu_composer"
calls:
- [setContainer, ["@service_container"]]
tags:
- { name: twig.extension }
twig_intl:
class: Twig_Extensions_Extension_Intl
@@ -41,6 +20,7 @@ services:
arguments:
- "@request_stack"
- "@translator.default"
Chill\MainBundle\Templating\TranslatableStringHelper: '@chill.main.helper.translatable_string'
chill.main.twig.translatable_string:
class: Chill\MainBundle\Templating\TranslatableStringTwig
@@ -75,15 +55,7 @@ services:
- "@doctrine.orm.entity_manager"
calls:
- [ setContainer, ["@service_container"]]
chill.main.security.authorization.helper:
class: Chill\MainBundle\Security\Authorization\AuthorizationHelper
arguments:
- "@security.role_hierarchy"
chill.main.role_provider:
class: Chill\MainBundle\Security\RoleProvider
chill.main.validator.role_scope_scope_presence:
class: Chill\MainBundle\Validation\Validator\RoleScopeScopePresence
arguments:

View File

@@ -0,0 +1,6 @@
services:
Chill\MainBundle\Controller\:
autowire: true
resource: '../../../Controller'
tags: ['controller.service_arguments']

View File

@@ -0,0 +1,4 @@
services:
Chill\MainBundle\DataFixtures\ORM\:
resource: ../../../DataFixtures/ORM
tags: [ 'doctrine.fixture.orm' ]

View File

@@ -54,9 +54,17 @@ services:
class: Chill\MainBundle\Form\Type\PostalCodeType
arguments:
- "@chill.main.helper.translatable_string"
- '@Symfony\Component\Routing\Generator\UrlGeneratorInterface'
- '@chill.main.form.choice_loader.postal_code'
- '@Symfony\Component\Translation\TranslatorInterface'
tags:
- { name: form.type }
chill.main.form.choice_loader.postal_code:
class: Chill\MainBundle\Form\ChoiceLoader\PostalCodeChoiceLoader
arguments:
- '@Chill\MainBundle\Repository\PostalCodeRepository'
chill.main.form.type.export:
class: Chill\MainBundle\Form\Type\Export\ExportType
arguments:

View File

@@ -0,0 +1,10 @@
services:
Chill\MainBundle\Routing\MenuBuilder\UserMenuBuilder:
tags:
- { name: 'chill.menu_builder' }
Chill\MainBundle\Routing\MenuBuilder\SectionMenuBuilder:
arguments:
$authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
tags:
- { name: 'chill.menu_builder' }

View File

@@ -5,6 +5,7 @@ services:
- "@request_stack"
- "@router"
- "%chill_main.pagination.item_per_page%"
Chill\MainBundle\Pagination\PaginatorFactory: '@chill_main.paginator_factory'
chill_main.paginator.twig_extensions:
class: Chill\MainBundle\Pagination\ChillPaginationTwig

View File

@@ -15,4 +15,13 @@ services:
class: Doctrine\ORM\EntityRepository
factory: ["@doctrine.orm.entity_manager", getRepository]
arguments:
- "Chill\\MainBundle\\Entity\\Scope"
- "Chill\\MainBundle\\Entity\\Scope"
chill.main.postalcode_repository:
class: Doctrine\ORM\EntityRepository
factory: ["@doctrine.orm.entity_manager", getRepository]
arguments:
- "Chill\\MainBundle\\Entity\\PostalCode"
Chill\MainBundle\Repository\PostalCodeRepository: '@chill.main.postalcode_repository'

View File

@@ -0,0 +1,24 @@
services:
chill.main.menu_composer:
class: Chill\MainBundle\Routing\MenuComposer
arguments:
- '@Symfony\Component\Routing\RouterInterface'
- '@Knp\Menu\FactoryInterface'
- '@Symfony\Component\Translation\TranslatorInterface'
Chill\MainBundle\Routing\MenuComposer: '@chill.main.menu_composer'
chill.main.routes_loader:
class: Chill\MainBundle\Routing\Loader\ChillRoutesLoader
arguments:
- "%chill_main.routing.resources%"
tags:
- { name: routing.loader }
chill.main.twig.chill_menu:
class: Chill\MainBundle\Routing\MenuTwig
arguments:
- "@chill.main.menu_composer"
calls:
- [setContainer, ["@service_container"]]
tags:
- { name: twig.extension }

View File

@@ -0,0 +1,23 @@
services:
chill.main.security.authorization.helper:
class: Chill\MainBundle\Security\Authorization\AuthorizationHelper
arguments:
$roleHierarchy: "@security.role_hierarchy"
$hierarchy: "%security.role_hierarchy.roles%"
$em: '@Doctrine\ORM\EntityManagerInterface'
Chill\MainBundle\Security\Authorization\AuthorizationHelper: '@chill.main.security.authorization.helper'
chill.main.role_provider:
class: Chill\MainBundle\Security\RoleProvider
chill.main.user_provider:
class: Chill\MainBundle\Security\UserProvider\UserProvider
arguments:
$em: '@Doctrine\ORM\EntityManagerInterface'
Chill\MainBundle\Security\Authorization\ChillExportVoter:
arguments:
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
tags:
- { name: security.voter }

View File

@@ -0,0 +1,13 @@
services:
chill_main.validator_user_circle_consistency:
class: Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistencyValidator
arguments:
- "@chill.main.security.authorization.helper"
tags:
- { name: "validator.constraint_validator" }
Chill\MainBundle\Validation\Validator\UserUniqueEmailAndUsername:
arguments:
$em: '@Doctrine\ORM\EntityManagerInterface'
tags:
- { name: "validator.constraint_validator" }

View File

@@ -0,0 +1,2 @@
services:
Chill\MainBundle\Templating\UI\CountNotificationUser: ~

View File

@@ -1,27 +1,32 @@
Chill\MainBundle\Entity\PermissionsGroup:
properties:
name:
name:
- NotBlank: ~
- Length:
max: 50
roleScopes:
- Valid: ~
constraints:
- Callback: [isRoleScopePresentOnce]
- Callback:
callback: isRoleScopePresentOnce
Chill\MainBundle\Entity\User:
properties:
username:
- Length:
- Length:
max: 70
min: 3
email:
- Email: ~
constraints:
- Callback: [isGroupCenterPresentOnce]
- Callback:
callback: isGroupCenterPresentOnce
- \Chill\MainBundle\Validation\Constraint\UserUniqueEmailAndUsernameConstraint: ~
Chill\MainBundle\Entity\RoleScope:
constraints:
- \Chill\MainBundle\Validation\Constraint\RoleScopeScopePresenceConstraint: ~
Chill\MainBundle\Entity\Center:
properties:
name:
@@ -41,11 +46,11 @@ Chill\MainBundle\Entity\Address:
validFrom:
- NotNull: ~
- Date: ~
Chill\MainBundle\Entity\PostalCode:
properties:
name:
- Length:
- Length:
max: 250
min: 2
code:
@@ -53,4 +58,4 @@ Chill\MainBundle\Entity\PostalCode:
min: 2
max: 100
country:
- NotNull: ~
- NotNull: ~

View File

@@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Add index to postal code
*/
final class Version20180703191509 extends AbstractMigration
{
public function up(Schema $schema) : void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
try {
$this->addSql('CREATE EXTENSION IF NOT EXISTS pg_trgm');
$this->addSql('CREATE INDEX search_name_code ON chill_main_postal_code USING GIN (LOWER(code) gin_trgm_ops, LOWER(label) gin_trgm_ops)');
} catch (\Exception $e) {
$this->skipIf(true, "Could not create extension pg_trgm");
}
}
public function down(Schema $schema) : void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('DROP INDEX search_name_code');
}
}

View File

@@ -0,0 +1,87 @@
<?php declare(strict_types=1);
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* add username and username canonical, email and email canonical columns
* to users
*/
final class Version20180709181423 extends AbstractMigration
{
public function up(Schema $schema) : void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE users ADD usernameCanonical VARCHAR(80) DEFAULT NULL');
$this->addSql('UPDATE users SET usernameCanonical=LOWER(UNACCENT(username))');
$this->addSql('ALTER TABLE users ALTER usernameCanonical DROP NOT NULL');
$this->addSql('ALTER TABLE users ALTER usernameCanonical SET DEFAULT NULL');
$this->addSql('ALTER TABLE users ADD email VARCHAR(150) DEFAULT NULL');
$this->addSql('ALTER TABLE users ADD emailCanonical VARCHAR(150) DEFAULT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E9F5A5DC32 ON users (usernameCanonical)');
$this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E9885281E ON users (emailCanonical)');
$this->addSql(<<<'SQL'
CREATE OR REPLACE FUNCTION canonicalize_user_on_update() RETURNS TRIGGER AS
$BODY$
BEGIN
IF NEW.username <> OLD.username OR NEW.email <> OLD.email OR OLD.emailcanonical IS NULL OR OLD.usernamecanonical IS NULL THEN
UPDATE users SET usernamecanonical=LOWER(UNACCENT(NEW.username)), emailcanonical=LOWER(UNACCENT(NEW.email)) WHERE id=NEW.id;
END IF;
RETURN NEW;
END;
$BODY$ LANGUAGE PLPGSQL
SQL
);
$this->addSql(<<<SQL
CREATE TRIGGER canonicalize_user_on_update
AFTER UPDATE
ON users
FOR EACH ROW
EXECUTE PROCEDURE canonicalize_user_on_update();
SQL
);
$this->addSql(<<<'SQL'
CREATE OR REPLACE FUNCTION canonicalize_user_on_insert() RETURNS TRIGGER AS
$BODY$
BEGIN
UPDATE users SET usernamecanonical=LOWER(UNACCENT(NEW.username)), emailcanonical=LOWER(UNACCENT(NEW.email)) WHERE id=NEW.id;
RETURN NEW;
END;
$BODY$ LANGUAGE PLPGSQL;
SQL
);
$this->addSql(<<<SQL
CREATE TRIGGER canonicalize_user_on_insert
AFTER INSERT
ON users
FOR EACH ROW
EXECUTE PROCEDURE canonicalize_user_on_insert();
SQL
);
}
public function down(Schema $schema) : void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('DROP INDEX UNIQ_1483A5E9F5A5DC32');
$this->addSql('DROP INDEX UNIQ_1483A5E9885281E');
$this->addSql('ALTER TABLE users DROP usernameCanonical');
$this->addSql('ALTER TABLE users DROP email');
$this->addSql('ALTER TABLE users DROP emailCanonical');
$this->addSql('DROP TRIGGER canonicalize_user_on_insert ON users');
$this->addSql('DROP FUNCTION canonicalize_user_on_insert()');
$this->addSql('DROP TRIGGER canonicalize_user_on_update ON users');
$this->addSql('DROP FUNCTION canonicalize_user_on_update()');
}
}

View File

@@ -4585,7 +4585,6 @@ header {
right: 0;
top: 0;
z-index: -1;
background-image: url("/bundles/chillmain/img/background/desert.jpg");
background-attachment: fixed;
background-repeat: no-repeat;
background-size: cover;

View File

@@ -93,7 +93,7 @@ var chill = function() {
*
* @param{string} form_id An identification string of the form
* @param{string} alert_message The alert message to display
* @param{boolean} check_unsaved_data If true display the alert message only when the form
* @param{boolean} check_unsaved_data If true display the alert message only when the form
* contains some modified fields otherwise always display the alert when leaving
* @return nothing
*/
@@ -123,12 +123,12 @@ var chill = function() {
});
}
/**
* Mark the choices "not specified" as check by default.
*
* This function apply to `custom field choices` when the `required`
/**
* Mark the choices "not specified" as check by default.
*
* This function apply to `custom field choices` when the `required`
* option is false and `expanded` is true (checkboxes or radio buttons).
*
*
* @param{string} choice_name the name of the input
*/
function checkNullValuesInChoices(choice_name) {
@@ -184,21 +184,21 @@ var chill = function() {
* child) of a given form : each parent option has a category, the
* child select only display options that have the same category of the
* parent optionn
*
* The parent must have the class "chill-category-link-parent".
*
*
* The parent must have the class "chill-category-link-parent".
*
* The children must have the class "chill-category-link-child". Each option
* of the parent must have the attribute `data-link-category`, with the value of
* the connected option in parent.
*
*
* Example :
*
*
* ```html
* <select name="country" class="chill-category-link-parent">
* <option value="BE">Belgium</option>
* <option value="FR">France</option>
* </select>
*
*
* <select name="cities">class="chill-category-link-children">
* <option value="paris" data-link-category="FR">Paris</option>
* <option value="toulouse" data-link-category="FR">Toulouse</option>
@@ -207,7 +207,7 @@ var chill = function() {
* <option value="mons" data-link-category="BE">Mons</option>
* </select>
* ```
*
*
* TODO ECRIRE LA DOC METTRE LES TESTS DANS git :
* tester que init est ok :
- quand vide
@@ -224,7 +224,7 @@ var chill = function() {
form.old_category = null;
form.link_parent = $(form).find('.chill-category-link-parent');
form.link_child = $(form).find('.chill-category-link-child');
// check if the parent allow multiple or single results
parent_multiple = $(form).find('.chill-category-link-parent').get(0).multiple;
// if we use select2, parent_multiple will be `undefined`
@@ -233,10 +233,10 @@ var chill = function() {
// we suppose that multiple is false (old behaviour)
parent_multiple = false
}
$(form.link_parent).addClass('select2');
$(form.link_parant).select2({allowClear: true}); // it is weird: when I fix the typo here, the whole stuff does not work anymore...
if (parent_multiple == false) {
form.old_category = null;
@@ -279,9 +279,9 @@ var chill = function() {
}
});
} else {
var i=0,
var i=0,
selected_items = $(form.link_parent).find(':selected');
form.old_categories = [];
for (i=0;i < selected_items.length; i++) {
form.old_categories.push(selected_items[i].value);
@@ -314,13 +314,13 @@ var chill = function() {
});
form.link_parent.change(function() {
var new_categories = [],
var new_categories = [],
selected_items = $(form.link_parent).find(':selected'),
visible;
for (i=0;i < selected_items.length; i++) {
new_categories.push(selected_items[i].value);
}
if(new_categories != form.old_categories) {
$(form.link_child).find('option')
.each(function(i,e) {
@@ -352,16 +352,16 @@ var chill = function() {
form.old_categories = new_categories;
}
});
}
}
});
}
function _displayHideTargetWithCheckbox(checkbox) {
var target = checkbox.dataset.displayTarget,
hideableElements;
hideableElements = document.querySelectorAll('[data-display-show-hide="' + target + '"]');
if (checkbox.checked) {
for (let i=0; i < hideableElements.length; i = i+1) {
hideableElements[i].style.display = "unset";
@@ -371,36 +371,36 @@ var chill = function() {
hideableElements[i].style.display = "none";
}
}
}
/**
* create an interaction between a checkbox and element to show if the
* create an interaction between a checkbox and element to show if the
* checkbox is checked, or hide if the checkbox is not checked.
*
* The checkbox must have the data `data-display-target` with an id,
*
* The checkbox must have the data `data-display-target` with an id,
* and the parts to show/hide must have the data `data-display-show-hide`
* with the same value.
*
* Example :
*
*
* Example :
*
* ```
* <input data-display-target="export_abc" value="1" type="checkbox">
*
*
* <div data-display-show-hide="export_abc">
* <!-- your content here will be hidden / shown according to checked state -->
* </div>
* ```
*
*
* Hint: for forms in symfony, you could use the `id` of the form element,
* accessible through `{{ form.vars.id }}`. This id should be unique.
*
*
*
*
* @returns {undefined}
*/
function listenerDisplayCheckbox() {
var elements = document.querySelectorAll("[data-display-target]");
for (let i=0; i < elements.length; i = i+1) {
elements[i].addEventListener("change", function(e) {
_displayHideTargetWithCheckbox(e.target);
@@ -421,3 +421,5 @@ var chill = function() {
listenerDisplayCheckbox: listenerDisplayCheckbox,
};
} ();
export { chill };

View File

@@ -0,0 +1,23 @@
div.chill-collection {
ul.chill-collection__list {
list-style: none;
padding: 0;
margin-bottom: 1.5rem;
li.chill-collection__list__entry:nth-child(2n) {
background-color: var(--chill-light-gray);
padding: 0.5rem 0;
}
// all entries, except the last one
li.chill-collection__list__entry:nth-last-child(1n+2) {
margin-bottom: 1rem;
}
}
button.chill-collection__button--add {
}
}

View File

@@ -0,0 +1,116 @@
/**
* Javascript file which handle ChillCollectionType
*
* Two events are emitted by this module, both on window and on collection / ul.
*
* Collection (an UL element) and entry (a li element) are associated with those
* events.
*
* ```
* window.addEventListener('collection-add-entry', function(e) {
* console.log(e.detail.collection);
* console.log(e.detail.entry);
* });
*
* window.addEventListener('collection-remove-entry', function(e) {
* console.log(e.detail.collection);
* console.log(e.detail.entry);
* });
*
* collection.addEventListener('collection-add-entry', function(e) {
* console.log(e.detail.collection);
* console.log(e.detail.entry);
* });
*
* collection.addEventListener('collection-remove-entry', function(e) {
* console.log(e.detail.collection);
* console.log(e.detail.entry);
* });
* ```
*/
require('./collection.scss');
class CollectionEvent {
constructor(collection, entry) {
this.collection = collection;
this.entry = entry;
}
}
/**
*
* @param {type} button
* @returns {handleAdd}
*/
var handleAdd = function(button) {
var
form_name = button.dataset.collectionAddTarget,
prototype = button.dataset.formPrototype,
collection = document.querySelector('ul[data-collection-name="'+form_name+'"]'),
entry = document.createElement('li'),
event = new CustomEvent('collection-add-entry', { detail: { collection: collection, entry: entry } }),
counter = collection.childNodes.length,
content
;
content = prototype.replace(new RegExp('__name__', 'g'), counter);
entry.innerHTML = content;
entry.classList.add('chill-collection__list__entry');
initializeRemove(collection, entry);
collection.appendChild(entry);
chill.initPikaday('fr');
collection.dispatchEvent(event);
window.dispatchEvent(event);
};
var initializeRemove = function(collection, entry) {
var
button = document.createElement('button'),
isPersisted = entry.dataset.collectionIsPersisted,
content = collection.dataset.collectionButtonRemoveLabel,
allowDelete = collection.dataset.collectionAllowDelete,
event = new CustomEvent('collection-remove-entry', { detail: { collection: collection, entry: entry } })
;
if (allowDelete === '0' && isPersisted === '1') {
return;
}
button.classList.add('sc-button', 'bt-delete');
button.textContent = content;
button.addEventListener('click', function(e) {
e.preventDefault();
entry.remove();
collection.dispatchEvent(event);
window.dispatchEvent(event);
});
entry.appendChild(button);
};
window.addEventListener('load', function() {
var
addButtons = document.querySelectorAll("button[data-collection-add-target]"),
collections = document.querySelectorAll("ul[data-collection-name]")
;
for (let i = 0; i < addButtons.length; i ++) {
let addButton = addButtons[i];
addButton.addEventListener('click', function(e) {
e.preventDefault();
handleAdd(e.target);
});
}
for (let i = 0; i < collections.length; i ++) {
let entries = collections[i].querySelectorAll(':scope > li');
for (let j = 0; j < entries.length; j ++) {
initializeRemove(collections[i], entries[j]);
}
}
});

View File

@@ -0,0 +1,3 @@
require("./layout.scss");

View File

@@ -0,0 +1,21 @@
nav.chill-breadcrumb {
ul.list.on-left {
li {
border-right: 10px solid var(--chill-red);
}
li.active {
border-right: 10px solid var(--chill-green);
}
li.past {
border-right: 10px solid var(--chill-blue);
}
li.no-jump{
border-right: 10px solid var(--chill-light-gray);
background-color: var(--chill-yellow);
padding: 0.3em 0.3em 0.3em 0.6em;
color: var(--chill-dark-gray);
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var mime = require('mime-types')
var download_report = (url, container) => {
var download_text = container.dataset.downloadText,
alias = container.dataset.alias;
window.fetch(url, { credentials: 'same-origin' })
.then(response => {
if (!response.ok) {
throw Error(response.statusText);
}
return response.blob();
}).then(blob => {
var content = URL.createObjectURL(blob),
link = document.createElement("a"),
type = blob.type,
hasForcedType = 'mimeType' in container.dataset,
extension;
if (hasForcedType) {
// force a type
type = container.dataset.mimeType;
blob = new Blob([ blob ], { 'type': type });
content = URL.createObjectURL(blob);
}
extension = mime.extension(type);
link.appendChild(document.createTextNode(download_text));
link.classList.add("sc-button", "btn-action");
link.href = content;
link.download = alias;
if (extension !== false) {
link.download = link.download + '.' + extension;
}
container.innerHTML = "";
container.appendChild(link);
}).catch(function(error) {
console.log(error);
var problem_text =
document.createTextNode("Problem during download");
container
.replaceChild(problem_text, container.firstChild);
});
};
module.exports = download_report;

View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
chill.download_report = require("./download-report.js");

View File

@@ -0,0 +1,3 @@
require('./login.scss');

View File

@@ -0,0 +1,63 @@
@import './../../fonts/OpenSans/OpenSans';
html, body {
height: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #333;
color: white;
text-align: center;
font-family: 'Open Sans';
}
#content {
position: relative;
height: 90%;
padding-top: 10%;
}
#content:before {
bottom: 0;
content: "";
left: 0;
opacity: 0.2;
position: absolute;
right: 0;
top: 0;
z-index: -1;
background-image: url('./../../img/background/desert.jpg');
background-attachment: fixed;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
label {
width : 15em;
text-align: right;
display: inline-block;
font-weight: 300;
padding-right: 5px;
}
input {
}
form {
}
button {
margin-left: 15em;
margin-top: 1em;
background-color: #df4949;
border: medium none;
border-radius: 0;
box-shadow: none;
color: #fff;
padding: 4px 8px;
font-family: 'Open Sans';
font-weight: 300;
}

View File

@@ -0,0 +1,36 @@
window.addEventListener('load', function (e) {
var
postalCodes = document.querySelectorAll('[data-postal-code]')
;
for (let i = 0; i < postalCodes.length; i++) {
let
searchUrl = postalCodes[i].dataset.searchUrl,
noResultsLabel = postalCodes[i].dataset.noResultsLabel,
errorLoadLabel = postalCodes[i].dataset.errorLoadLabel,
searchingLabel = postalCodes[i].dataset.searchingLabel
;
$(postalCodes[i]).select2({
allowClear: true,
language: {
errorLoading: function () {
return errorLoadLabel;
},
noResults: function () {
return noResultsLabel;
},
searching: function () {
return searchingLabel;
}
},
ajax: {
url: searchUrl,
dataType: 'json',
delay: 250
}
});
}
});

View File

@@ -1,4 +1,7 @@
// YOUR CUSTOM SCSS
@import 'custom/config/colors';
@import 'custom/config/variables';
@import 'custom/fonts';
@import 'custom/timeline';
@import 'custom/mixins/entity';
@import 'custom/activity';
@@ -11,7 +14,7 @@
@import 'custom/flash_messages';
html,body {
html,body {
min-height:100%;
font-family: 'Open Sans';
}
@@ -34,7 +37,7 @@ header {
right: 0;
top: 0;
z-index: -1;
background-image: url("/bundles/chillmain/img/background/desert.jpg");
background-image: url('./../../img/background/desert.jpg');
background-attachment: fixed;
background-repeat: no-repeat;
background-size: cover;
@@ -74,18 +77,14 @@ ul.custom_fields.choice li {
color: $red;
}
.blop label {
line-height: 1 + ($base-spacing / 3);
}
.footer {
p {
font-family: 'Open Sans';
font-weight: 300;
}
a {
color: white;
a {
color: white;
text-decoration: underline;
}
}
@@ -97,7 +96,7 @@ ul.custom_fields.choice li {
display: inline-block;
text-align: center;
}
.separator {
margin-left: 0.2em;
margin-right: 0.2em;
@@ -107,7 +106,7 @@ ul.custom_fields.choice li {
.open_sansbold {
font-family: 'Open Sans';
font-weight: bold;
}
@@ -140,21 +139,21 @@ div.input_with_post_text input {
dl.chill_report_view_data,
dl.chill_view_data {
dt {
margin-top: 1.5em;
color: $chill-blue;
}
dd {
padding-left: 1.5em;
margin-top: 0.2em;
ul {
padding-left: 0;
}
}
}
@@ -164,13 +163,13 @@ blockquote.chill-user-quote {
padding: 0.5em 10px;
quotes: "\201C""\201D""\2018""\2019";
background-color: $chill-llight-gray;
p { display: inline; }
}
.chill-no-data-statement {
font-style: italic;
}

View File

@@ -4,11 +4,11 @@
// note that other level are defined in modules/_alerts.scss
.alert {
// override in modules/_alerts.scss
@include alert($red);
}
.warning {
@include alert($orange);
}
// .alert {
// // override in modules/_alerts.scss
// @include alert($red);
// }
//
// .warning {
// @include alert($orange);
// }

View File

@@ -0,0 +1,2 @@
@import './../../fonts/OpenSans/OpenSans';

View File

@@ -6,29 +6,36 @@ ul.record_actions li {
display: inline-block;
}*/
ul.record_actions {
ul.record_actions, ul.record_actions_column {
display: flex;
flex-direction: row;
justify-content: flex-end;
padding: 0.5em 0;
li {
display: inline-block;
list-style-type: none;
margin-right: 1em;
order: 99;
&:last-child {
margin-right: 0;
}
}
li.cancel {
order: 1;
margin-right: auto;
}
}
ul.record_actions {
flex-direction: row;
}
ul.record_actions_column {
flex-direction: column;
}
ul.record_actions.sticky-form-buttons {
@@ -42,4 +49,4 @@ td ul.record_actions,
li {
margin-right: 0.2em;
}
}
}

View File

@@ -6,11 +6,13 @@ $chill-yellow: #eec84a;
$chill-orange: #e2793d;
$chill-red: #df4949;
$chill-gray: #ececec;
$chill-beige :#cabb9f;
$chill-pink :#dd506d;
$chill-beige: #cabb9f;
$chill-pink: #dd506d;
$chill-dark-gray: #333333;
$chill-light-gray: #b2b2b2;
$chill-llight-gray: $grey-10;
$chill-llight-gray: #e6e6e6;
$dark-grey: $chill-dark-gray;
$color-name: "blue" "green" "green-dark" "yellow" "orange" "red" "gray" "beige" "pink" "dark-gray" "light-gray";
$color-code: #334d5c #43b29d #328474 #eec84a #e2793d #df4949 #ececec #cabb9f #dd506d #333333 #b2b2b2;
@@ -27,3 +29,37 @@ $green: $chill-green;
$blue: $chill-blue;
$yellow: $chill-yellow;
$black: #111111;
$white: #ffffff;
$light-grey: $chill-light-gray;
/*
due to a bug in sass, we must re-declare the variable in css
(use of a sass variable after -- does not work)
*/
:root {
--chill-blue: #334d5c;
--chill-green: #43b29d;
--chill-green-dark: #328474;
--chill-yellow: #eec84a;
--chill-orange: #e2793d;
--chill-red: #df4949;
--chill-gray: #ececec;
--chill-beige: #cabb9f;
--chill-pink: #dd506d;
--chill-dark-gray: #333333;
--chill-light-gray: #b2b2b2;
--chill-llight-gray: #e6e6e6;
--dark-grey: #333333;
--orange: #e2793d;
--red: #df4949;
--green: #43b29d;
--blue: #334d5c;
--yellow: #eec84a;
--black: #111111;
--white: #ffffff;
--light-grey: #b2b2b2;
}

View File

@@ -1,27 +1,27 @@
.sc-button {
&.bt-submit, &.bt-save, &.bt-create, &.bt-new {
@include button($green, $white);
@include button($green, $white);
}
&.bt-reset, &.bt-delete {
@include button($red, $white);
@include button($red, $white);
}
&.bt-action, &.bt-edit, &.bt-update {
@include button($orange, $white);
@include button($orange, $white);
}
&.bt-show, &.bt-view {
@include button($blue, $white);
}
&:not(.change-icon) {
&.bt-create::before,
&.bt-create::before,
&.bt-save::before,
&.bt-new::before,
&.bt-delete::before,
&.bt-update::before,
&.bt-new::before,
&.bt-delete::before,
&.bt-update::before,
&.bt-edit::before,
&.bt-cancel::before,
&.bt-view::before,
@@ -52,7 +52,7 @@
&.bt-cancel::before {
// add an arrow left
content: "";
content: "";
}
&.bt-show::before, &.bt-view::before {
@@ -70,11 +70,11 @@
margin-right: 0;
}
&:not(.change-icon) {
&.bt-create::before,
&.bt-create::before,
&.bt-save::before,
&.bt-new::before,
&.bt-delete::before,
&.bt-update::before,
&.bt-new::before,
&.bt-delete::before,
&.bt-update::before,
&.bt-edit::before,
&.bt-cancel::before,
&.bt-view::before,
@@ -83,13 +83,13 @@
}
}
}
&.has-hidden > span.show-on-hover {
display: none;
}
&.has-hidden:hover {
> span.show-on-hover {
display: inline-block;
}
@@ -97,13 +97,13 @@
> i.fa {
margin-right: 0.5em;
}
&:not(.change-icon) {
&.bt-create::before,
&.bt-create::before,
&.bt-save::before,
&.bt-new::before,
&.bt-delete::before,
&.bt-update::before,
&.bt-new::before,
&.bt-delete::before,
&.bt-update::before,
&.bt-edit::before,
&.bt-cancel::before,
&.bt-view::before,
@@ -144,4 +144,4 @@
.sticky-form-buttons .margin-10 {
margin-left: 10%;
margin-right: 10%;
}
}

View File

@@ -6,4 +6,23 @@ textarea {
span.force-inline-label label {
display: inline;
}
.chill-form-money {
display: flex;
flex-direction: row;
justify-content: flex-end;
span.chill-form-money__money {
align-self: center;
margin-left: 1em;
}
}
.chill-form__errors {
.chill-form_errors__entry.chill-form__errors__entry--warning {
color: var(--chill-green-dark);
}
}

View File

@@ -1,52 +1,88 @@
.navigation {
background-color: $chill-blue;
background-color: $chill-blue;
a.more:after {
color: $chill-dark-gray;
}
a.more:after {
color: $chill-dark-gray;
}
li.nav-link2 {
a {
margin-bottom: 2px;
}
li.nav-link2 {
a {
margin-bottom: 2px;
}
&.lang-selection {
color: $chill-light-gray;
font-size: 0.7em;
a.more:after {
&.lang-selection {
color: $chill-light-gray;
}
}
font-size: 0.7em;
ul {
top: 58px;
a.more:after {
color: $chill-light-gray;
}
}
a {
padding-left: 0;
}
}
}
ul {
top: 58px;
div.nav, div.navigation-search {
float: right;
a {
padding-left: 0;
}
}
}
input[type=search] {
padding: 0.2em;
float: left;
div.nav, div.navigation-search {
float: right;
border: none;
}
button {
color: $chill-light-gray;
background-color: $chill-blue;
padding: 0 0 0 7px;
top: inherit;
font-size: 1.2em;
position: unset;
float: left;
}
}
input[type=search] {
padding: 0.2em;
float: left;
border: none;
}
button {
color: $chill-light-gray;
background-color: $chill-blue;
padding: 0 0 0 7px;
top: inherit;
font-size: 1.2em;
position: unset;
float: left;
}
}
li.user-menu {
min-width: 14rem;
}
ul.user-menu-list {
li.user-menu__entry {
display: block;
background-color: $chill-dark-gray;
border-bottom: 1px solid #FFF;
padding-top: 0;
padding-bottom: 0;
line-height: 2;
}
li.user-menu__entry--warning-entry {
background-color: $chill-red;
font-weight: 700;
}
}
span.notification-counter {
display: inline-block;
padding: .25em .6em .25rem .6em;
font-size: 100%;
line-height: 1;
text-align: center;
white-space: nowrap;
border-radius: 10rem;
background-color: $chill-red;
color: $white;
font-weight: 700;
margin-left: .5rem;
}
}

View File

@@ -17,6 +17,8 @@ class AppKernel extends Kernel
new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
new Symfony\Bundle\DebugBundle\DebugBundle()
);
}

View File

@@ -41,7 +41,6 @@ security:
form_login:
csrf_parameter: _csrf_token
csrf_token_id: authenticate
csrf_provider: form.csrf_provider
logout: ~

View File

@@ -31,7 +31,8 @@ not valid: non valide
Confirm: Confirmer
Cancel: Annuler
Save: Enregistrer
This form contains errors: Ce formulaire contient des erreurs
Choose an user: Choisir un utilisateur
'You are going to leave a page with unsubmitted data. Are you sure you want to leave ?': "Vous allez quitter la page alors que des données n'ont pas été enregistrées. Êtes vous sûr de vouloir partir ?"
Edit: Modifier
@@ -63,7 +64,9 @@ Advanced search: Recherche avancée
#admin
Create: Créer
show: voir
Show: Voir
edit: modifier
Edit: Modifier
Main admin menu: Menu d'administration principal
Actions: Actions
Users and permissions: Utilisateurs et permissions
@@ -179,4 +182,9 @@ column: colonne
Comma separated values (CSV): Valeurs séparées par des virgules (CSV - tableur)
# spreadsheet formatter
Choose the format: Choisir le format
Choose the format: Choisir le format
# select2
'select2.no_results': Aucun résultat
'select2.error_loading': Erreur de chargement des résultats
'select2.searching': Recherche en cours...

View File

@@ -5,4 +5,7 @@ The role "%role%" should not be associated with a scope.: Le rôle "%role%" ne d
"The password must contains one letter, one capitalized letter, one number and one special character as *[@#$%!,;:+\"'-/{}~=µ()£]). Other characters are allowed.": "Le mot de passe doit contenir une majuscule, une minuscule, et au moins un caractère spécial parmi *[@#$%!,;:+\"'-/{}~=µ()£]). Les autres caractères sont autorisés."
The password fields must match: Les mots de passe doivent correspondre
A permission is already present for the same role and scope: Une permission est déjà présente pour le même rôle et cercle.
A permission is already present for the same role and scope: Une permission est déjà présente pour le même rôle et cercle.
#UserCircleConsistency
"{{ username }} is not allowed to see entities published in this circle": "{{ username }} n'est pas autorisé à voir l'élément publié dans ce cercle."

View File

@@ -27,50 +27,8 @@ window.addEventListener("DOMContentLoaded", function(e) {
query = window.location.search,
container = document.querySelector("#download_container")
;
window.fetch(url+query, { credentials: 'same-origin' })
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.blob();
}).then(function(blob) {
var content = URL.createObjectURL(blob),
link = document.createElement("a"),
suffix_file;
switch (blob.type) {
case 'application/vnd.oasis.opendocument.spreadsheet':
suffix_file = '.ods';
break;
case 'text/csv':
suffix_file = '.csv';
break;
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
suffix_file = '.xlsx';
break;
default:
suffix_file = '';
}
link.appendChild(document.createTextNode("{{ "Download your report"|trans }}"));
link.classList.add("sc-button", "btn-action");
link.href = content;
link.download = "{{ alias }}"+suffix_file;
let waiting_text = container.querySelector("#waiting_text");
container.removeChild(waiting_text);
container.appendChild(link);
}).catch(function(error) {
var problem_text =
document.createTextNode("{{ "Problem during download"|trans }}");
container
.replaceChild(problem_text, container.firstChild);
})
;
chill.download_report(url+query, container);
});
</script>
{% endblock %}
@@ -79,6 +37,6 @@ window.addEventListener("DOMContentLoaded", function(e) {
<h1>{{ "Download export"|trans }}</h1>
<div id="download_container"><span id="waiting_text">{{ "Waiting for your report"|trans }}...</span></div>
<div id="download_container" data-alias="{{ alias|escape('html_attr') }}" {% if mime_type is defined %}data-mime-type="{{ mime_type|escape('html_attr') }}"{% endif %} data-download-text="{{ "Download your report"|trans|escape('html_attr') }}"><span id="waiting_text">{{ "Waiting for your report"|trans }}...</span></div>
{% endblock %}

View File

@@ -61,7 +61,11 @@
<br/>
{% endfor %}
</div>
<script type="text/javascript">chill.checkNullValuesInChoices("{{ form.vars.full_name }}");</script>
<script type="text/javascript">
document.addEventListener('load', function(e) {
chill.checkNullValuesInChoices("{{ form.vars.full_name }}");
});
</script>
{% endspaceless %}
{% endblock choice_widget_expanded %}
@@ -90,11 +94,20 @@
{%- endif -%}
{% endfor %}
<script type="text/javascript">
chill.checkNullValuesInChoices("{{ form._choices.vars.full_name }}");
document.addEventListener('load', function(e) {
chill.checkNullValuesInChoices("{{ form._choices.vars.full_name }}");
});
</script>
{% endspaceless %}
{% endblock choice_with_other_widget %}
{% block money_widget %}
<div class="chill-form-money">
{{ block('form_widget_simple') }}
<span class="chill-form-money__money">{{ money_pattern|form_encode_currency }}</span>
</div>
{% endblock money_widget %}
{% block date_widget %}
{% spaceless %}
@@ -128,9 +141,9 @@
{% block form_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<ul class="errors">
<ul class="errors chill-form__errors">
{% for error in errors %}
<li>{{ error.message }}</li>
<li class="chill-form_errors__entry {% if 'severity' in error.cause.constraint.payload|keys %}chill-form__errors__entry--{{ error.cause.constraint.payload.severity }}{% endif %}">{{ error.message }}</li>
{% endfor %}
</ul>
{% endif %}
@@ -152,3 +165,21 @@
{{ form_row(form.order) }}
{% endblock %}
{% block chill_collection_widget %}
<div class="chill-collection">
<ul class="chill-collection__list" data-collection-name="{{ form.vars.name|escape('html_attr') }}" data-collection-identifier="{{ form.vars.identifier|escape('html_attr') }}" data-collection-button-remove-label="{{ form.vars.button_remove_label|trans|e }}" data-collection-allow-add="{{ form.vars.allow_add|escape('html_attr') }}" data-collection-allow-delete="{{ form.vars.allow_delete|escape('html_attr') }}" >
{% for entry in form %}
<li class="chill-collection__list__entry" data-collection-is-persisted="1">
<div>
{{ form_widget(entry) }}
</div>
</li>
{% endfor %}
</ul>
{% if form.vars.allow_add == 1 %}
<button class="chill-collection__button--add sc-button" data-collection-add-target="{{ form.vars.name|escape('html_attr') }}" data-form-prototype="{{ ('<div>' ~ form_widget(form.vars.prototype) ~ '</div>')|escape('html_attr') }}" >{{ form.vars.button_add_label|trans }}</button>
</div>
{% endif %}
{% endblock %}

View File

@@ -23,81 +23,16 @@
<title>
{{ 'Login to %installation_name%' | trans({ '%installation_name%' : installation.name } ) }}
</title>
<link rel="shortcut icon" href="/bundles/chillmain/img/favicon.ico" type="image/x-icon">
{% stylesheets output="css/login.css" filter="cssrewrite"
"bundles/chillmain/fonts/OpenSans/OpenSans.css" %}
<link rel="stylesheet" href="{{ asset_url }}"/>
{% endstylesheets %}
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #333;
color: white;
text-align: center;
}
#content {
position: relative;
height: 90%;
padding-top: 10%;
}
#content:before {
bottom: 0;
content: "";
left: 0;
opacity: 0.2;
position: absolute;
right: 0;
top: 0;
z-index: -1;
background-image: url("/bundles/chillmain/img/background/desert.jpg");
background-attachment: fixed;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
label {
width : 15em;
text-align: right;
display: inline-block;
font-family: 'Open Sans';
font-weight: 300;
padding-right: 5px;
}
input {
}
form {
}
button {
margin-left: 15em;
margin-top: 1em;
background-color: #df4949;
border: medium none;
border-radius: 0;
box-shadow: none;
color: #fff;
padding: 4px 8px;
font-family: 'Open Sans';
font-weight: 300;
}
</style>
<link rel="shortcut icon" href="{{ asset('build/images/favicon.ico') }}" type="image/x-icon">
<link rel="stylesheet" href="{{ asset('build/login.css') }}"/>
</head>
<body>
<div id="content">
<img class="logo" src="/bundles/chillmain/img/logo-chill-outil-accompagnement_white.png">
<img class="logo" src="{{ asset('build/images/logo-chill-outil-accompagnement_white.png') }}">
<p>{{ error|trans }}</p>
{% if error is not null %}
<p>{{ error.message|trans }}</p>
{% endif %}
<form method="POST" action="{{ path('login_check') }}">
<label for="_username">{{ 'Username'|trans }}</label>

View File

@@ -21,16 +21,18 @@
<a href="javascript:void(0)" class="more">Sections</a>
</div>
<ul class="submenu width-15-em" style="padding-left: 0; padding-right: 0; background-color:transparent;">
{% for route in routes %}
{% for menu in menus %}
<li style="display:block; background-color: #333333; padding-left:1.5em; border-bottom:1px; border-bottom: 1px solid #FFF;padding-top:0; padding-bottom:0;">
<div style="margin-bottom:2px;">
<div style="font-family: 'Open Sans'; font-weight:300; font-size: 0.75em; text-align:left; height: 46px; display:inline-block; width: calc(100% - 5em - 1px); vertical-align:top;">
<a href="{{ path(route.key, args ) }}">{{ route.label|trans }}</a>
<a href="{{ menu.uri }}">{{ menu.label|trans }}</a>
</div>
<div style="background-color: #333333; text-align:center;width: 2em; margin-left:-0.15em; font-size:1.5em; color:#FFF; height: 46px; display:inline-block; vertical-align:top;float:right">{% spaceless %}
{% for icon in route.icons %}
{% if menu.extras.icons is defined %}
{% for icon in menu.extras.icons %}
<i class="fa fa-{{ icon }}"></i>
{% endfor %}
{% endif %}
{% endspaceless %}</div>
</div>
</li>

View File

@@ -1,5 +1,5 @@
{#
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
<info@champs-libres.coop> / <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
@@ -16,16 +16,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
<li class="nav-link2">
<li class="nav-link2 user-menu">
<div class="li-content">
<a href="javascript:void(0)" style="font-size: 0.8em; font-family: 'Open Sans'; font-weight:300;">
{{ 'Welcome' | trans }}<br/>
<b>{{ app.user.username }}</b>
<b>{{ app.user.username }}{{ render(controller('ChillMainBundle:UI:showNotificationUserCounter')) }}</b>
</a>
</div>
<ul class="submenu width-11-em">
{% for route in routes %}
<li><a href="{{ path(route.key, args ) }}" style="font-family: 'Open Sans'; font-weight:300; font-size: 0.9em;"><i class="fa fa-{{ route.icon }}"></i> {{ route.label|trans }}</a></li>
<ul class="submenu width-11-em user-menu-list" style="padding-left: 0; padding-right: 0; background-color:transparent;">
{% for menu in menus %}
<li style="display:block; background-color: #333333; padding-left:1.5em; border-bottom:1px; border-bottom: 1px solid #FFF;padding-top:0; padding-bottom:0;">
<div style="margin-bottom:2px;">
<div style="font-family: 'Open Sans'; font-weight:300; font-size: 0.75em; text-align:left; height: 46px; display:inline-block; width: calc(100% - 5em - 1px); vertical-align:top;">
<a href="{{ menu.uri }}">{{ menu.label|trans }}</a>
</div>
<div style="background-color: #333333; text-align:center;width: 2em; margin-left:-0.15em; font-size:1.5em; color:#FFF; height: 46px; display:inline-block; vertical-align:top;float:right">{% spaceless %}
{% if menu.extras.icon is defined %}
<i class="fa fa-{{ menu.extras.icon }}"></i>
{% endif %}
{% endspaceless %}</div>
</div>
</li>
{% endfor %}
</ul>
</li>

View File

@@ -0,0 +1 @@
{% if nb > 0 %}<span class="notification-counter">{{ nb }}{% endif %}

View File

@@ -8,6 +8,7 @@
{{ form_start(edit_form) }}
{{ form_row(edit_form.username) }}
{{ form_row(edit_form.email) }}
{{ form_row(edit_form.enabled, { 'label': "User'status"}) }}
{{ form_widget(edit_form.submit, { 'attr': { 'class' : 'sc-button green center' } } ) }}

View File

@@ -7,6 +7,7 @@
{{ form_start(form) }}
{{ form_row(form.username) }}
{{ form_row(form.email) }}
{{ form_row(form.plainPassword.password) }}
{{ form_widget(form.submit, { 'attr' : { 'class': 'sc-button blue' } }) }}
{{ form_end(form) }}

View File

@@ -1,5 +1,5 @@
{#
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
<info@champs-libres.coop> / <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
@@ -22,19 +22,13 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<head>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ installation.name }} - {% block title %}{% endblock %}</title>
<link rel="shortcut icon" href="/bundles/chillmain/img/favicon.ico" type="image/x-icon">
{% stylesheets output="css/all.css" filter="cssrewrite"
"bundles/chillmain/css/scratch.css"
"bundles/chillmain/css/chillmain.css"
"bundles/chillmain/css/select2/select2.css"
"bundles/chillmain/fonts/OpenSans/OpenSans.css"
"bundles/chillmain/css/pikaday.css" %}
<link rel="stylesheet" href="{{ asset_url }}"/>
{% endstylesheets %}
<link rel="shortcut icon" href="{{ asset('build/images/favicon.ico') }}" type="image/x-icon">
<link rel="stylesheet" href="{{ asset('build/chill.css') }}"/>
{% block css%}<!-- nothing added to css -->{% endblock %}
</head>
@@ -43,7 +37,7 @@
<div class="grid-4 hide-tablet hide-mobile parent">
<div class="grid-10 push-2 grid-tablet-12 grid-mobile-12 push-tablet-0 grid-mobile-0 logo-container">
<a href="{{ path('chill_main_homepage') }}">
<img class="logo" src="/bundles/chillmain/img/logo-chill-sans-slogan_white.png">
<img class="logo" src="{{ asset('build/images/logo-chill-sans-slogan_white.png') }}">
</a>
</div>
</div>
@@ -107,7 +101,7 @@
</span>
</div>
{% endfor %}
{% for flashMessage in app.session.flashbag.get('error') %}
<div class="grid-8 centered error flash_message">
<span>
@@ -115,14 +109,14 @@
</span>
</div>
{% endfor %}
{% for flashMessage in app.session.flashbag.get('notice') %}
<div class="grid-8 centered notice flash_message">
<span>
{{ flashMessage|raw }}
</span>
</div>
{% endfor %}
{% endfor %}
{% block content %}
<div class="container">
@@ -137,12 +131,12 @@
</form>
</div>
</div>
<div class="homepage_widget">
{{ chill_widget('homepage', {} ) }}
</div>
{% endblock %}
</div>
</div>
{% endblock %}
</div>
@@ -150,16 +144,8 @@
<p>{{ 'This program is free software: you can redistribute it and/or modify it under the terms of the <strong>GNU Affero General Public License</strong>'|trans|raw }}
<br/> <a href="https://{{ app.request.locale }}.wikibooks.org/wiki/Chill">{{ 'User manual'|trans }}</a></p>
</footer>
{% javascripts output="js/libs.js"
"bundles/chillmain/js/jquery.js"
"bundles/chillmain/js/moment.js"
"bundles/chillmain/js/pikaday/pikaday.js"
"bundles/chillmain/js/select2/select2.js"
"bundles/chillmain/js/pikaday/plugins/pikaday.jquery.js"
"bundles/chillmain/js/chill.js" %}
<script src="{{ asset_url }}" type="text/javascript"></script>
{% endjavascripts %}
<script type="text/javascript" src="{{ asset('build/chill.js') }}"></script>
<script type="text/javascript">
chill.initPikaday('{{ app.request.locale }}');