|
|
|
## Decorateurs
|
|
|
|
|
|
|
|
### Usage
|
|
|
|
|
|
|
|
On ne définit qu'un seul décorateur, qui hérite de la classe `AF83::Decorator`.
|
|
|
|
Il est responsable de décorer les collections ainsi que les instances.
|
|
|
|
Dans les controlleurs, le code devient donc simplement:
|
|
|
|
```ruby
|
|
|
|
# dans l'index
|
|
|
|
@items = ItemDecorator.decorator(@items)
|
|
|
|
|
|
|
|
# dans le show
|
|
|
|
@item = @item.decorate
|
|
|
|
```
|
|
|
|
Les actions disponibles sur la __collection__ sont définies à la racine du décorateur,
|
|
|
|
alors que celles attachées aux instances sont définies à l'aide du block `with_instance_decorator`.
|
|
|
|
|
|
|
|
Pour définir une action, on utilise la méthode `action_link`. Les options disponibles sont:
|
|
|
|
- `on`: limite la visibilité du lien aux actions listées (`on: %i(show index)`)
|
|
|
|
- `if`: reçoit une `Proc`, et n'affiche le lien que si le résultat est _trueish_
|
|
|
|
- `policy`: le lien n'est accessible que si l'utilisateur courant dispose du droit correspondant sur l'objet décoré (on ne passe que le nom de la permission : `edit`, `create`, etc.)
|
|
|
|
- `feature`: comme pour `policy`, mais avec une `feature`
|
|
|
|
- `weight`: pour modifier l'ordre d'affichage des liens (par défaut l'ordre de déclaration est utilisé)
|
|
|
|
|
|
|
|
Les actions sont aussi réparties dans des __groupes__. Il y a plusieurs syntaxes possibles pour cela:
|
|
|
|
```ruby
|
|
|
|
groups: { primary: true, secondary: %i(index show), any_other_group: :index)}
|
|
|
|
```
|
|
|
|
|
|
|
|
Des raccourcis sont disponibles pour les groupes `primary`, `secondary` et `footer`.
|
|
|
|
On peut dont écrire `action_link primary: :index` plutôt que `action_link groups: {primary: :index}`
|
|
|
|
|
|
|
|
Le contenu du lien est défini à l'aide d'un bloc (cf exemple).
|
|
|
|
Chaque méthode appelée sur l'objet passé au bloc est convertie en attribut sur la balise HTML résultante,
|
|
|
|
à l'exception de certaines méthodes spécifiques:
|
|
|
|
- `extra_class`: ajoute une (ou des) classe(s) au lien. Peut recevoir un tableau ou une string.
|
|
|
|
- `class`: __REMPLACE__ les classes du lien. Peut recevoir un tableau ou une string.
|
|
|
|
- `type`: permet de définir le type de balise HTML à utiliser. Seule la valeur `button` est implémentée, les autres _fallback_ sur un `<a>`
|
|
|
|
|
|
|
|
#### Raccourcis
|
|
|
|
|
|
|
|
4 méthodes sont disponibles pour définir des actions _communes_:
|
|
|
|
- `create_action_link`: pour ajouter un lien de création d'un objet sur une collection
|
|
|
|
- `show_action_link`: pour ajouter un lien d'affichage d'un objet sur une instance
|
|
|
|
- `edit_action_link`: pour ajouter un lien de modification d'un objet sur une instance
|
|
|
|
- `destroy_action_link`: pour ajouter un lien de suppression d'un objet sur une instance
|
|
|
|
|
|
|
|
Ils sont définis dans la classe `AF83::EnhancedDecorator`.
|
|
|
|
|
|
|
|
### Comportement
|
|
|
|
|
|
|
|
Le comportement par défaut est le suivant:
|
|
|
|
|
|
|
|
#### Sur la page `index`
|
|
|
|
|
|
|
|
Dans la zone principale du header (qui est reprise dans le header _sticky_), on affiche les actions
|
|
|
|
du groupe `primary` de la collection.
|
|
|
|
Dans la zone secondaire du header (sous la one principale), on affiche les actions
|
|
|
|
du groupe `secondary` de la collection.
|
|
|
|
Dans le TableBuilderHelper, on affiche toutes les actions des groupes `primary`, `secondary` et `footer` sur chaque instance,
|
|
|
|
groupées par groupe. A noter, le groupe `footer` est systématiquement affiché en dernier.
|
|
|
|
|
|
|
|
#### Sur la page `show`
|
|
|
|
|
|
|
|
Dans la zone principale du header (qui est reprise dans le header _sticky_), on affiche les actions
|
|
|
|
du groupe `primary` de l'objet.
|
|
|
|
Dans la zone secondaire du header (sous la one principale), on affiche les actions
|
|
|
|
du groupe `secondary` de l'objet.
|
|
|
|
|
|
|
|
|
|
|
|
### Exemples
|
|
|
|
|
|
|
|
#### Decorateur simple
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
class CalendarDecorator < AF83::Decorator
|
|
|
|
decorates Calendar
|
|
|
|
|
|
|
|
create_action_link
|
|
|
|
|
|
|
|
with_instance_decorator do |instance_decorator|
|
|
|
|
instance_decorator.show_action_link
|
|
|
|
instance_decorator.edit_action_link
|
|
|
|
instance_decorator.destroy_action_link do |l|
|
|
|
|
l.data {{ confirm: h.t('calendars.actions.destroy_confirm') }}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Decorateur plus complexe
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
class LineDecorator < AF83::Decorator
|
|
|
|
decorates Chouette::Line
|
|
|
|
|
|
|
|
create_action_link do |l|
|
|
|
|
l.content t('lines.actions.new')
|
|
|
|
l.href { h.new_line_referential_line_path(context[:line_referential]) }
|
|
|
|
end
|
|
|
|
|
|
|
|
with_instance_decorator do |instance_decorator|
|
|
|
|
instance_decorator.show_action_link do |l|
|
|
|
|
l.content t('lines.actions.show')
|
|
|
|
l.href { [context[:line_referential], object] }
|
|
|
|
end
|
|
|
|
|
|
|
|
instance_decorator.action_link do |l|
|
|
|
|
l.content t('lines.actions.show_network')
|
|
|
|
l.href { [context[:line_referential], object.network] }
|
|
|
|
end
|
|
|
|
|
|
|
|
instance_decorator.action_link do |l|
|
|
|
|
l.content t('lines.actions.show_company')
|
|
|
|
l.href { [context[:line_referential], object.company] }
|
|
|
|
l.disabled { object.company.nil? }
|
|
|
|
end
|
|
|
|
|
|
|
|
can_edit_line = ->(){ h.policy(Chouette::Line).create? && context[:line_referential].organisations.include?(context[:current_organisation]) }
|
|
|
|
|
|
|
|
instance_decorator.with_condition can_edit_line do
|
|
|
|
edit_action_link do |l|
|
|
|
|
l.content {|l| l.primary? ? h.t('actions.edit') : h.t('lines.actions.edit') }
|
|
|
|
l.href { h.edit_line_referential_line_path(context[:line_referential], object.id) }
|
|
|
|
end
|
|
|
|
|
|
|
|
action_link on: :index, secondary: :index do |l|
|
|
|
|
l.content t('lines.actions.new')
|
|
|
|
l.href { h.new_line_referential_line_path(context[:line_referential]) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
instance_decorator.action_link policy: :deactivate, secondary: :show, footer: :index do |l|
|
|
|
|
l.content { h.deactivate_link_content('lines.actions.deactivate') }
|
|
|
|
l.href { h.deactivate_line_referential_line_path(context[:line_referential], object) }
|
|
|
|
l.method :put
|
|
|
|
l.data confirm: h.t('lines.actions.deactivate_confirm')
|
|
|
|
l.extra_class "delete-action"
|
|
|
|
end
|
|
|
|
|
|
|
|
instance_decorator.action_link policy: :activate, secondary: :show, footer: :index do |l|
|
|
|
|
l.content { h.activate_link_content('lines.actions.activate') }
|
|
|
|
l.href { h.activate_line_referential_line_path(context[:line_referential], object) }
|
|
|
|
l.method :put
|
|
|
|
l.data confirm: h.t('lines.actions.activate_confirm')
|
|
|
|
l.extra_class "delete-action"
|
|
|
|
end
|
|
|
|
|
|
|
|
instance_decorator.destroy_action_link do |l|
|
|
|
|
l.content { h.destroy_link_content('lines.actions.destroy') }
|
|
|
|
l.href { h.line_referential_line_path(context[:line_referential], object) }
|
|
|
|
l.data confirm: h.t('lines.actions.destroy_confirm')
|
|
|
|
l.extra_class "delete-action"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
## Breadcrumb
|
|
|
|
|
|
|
|
Le fil d'ariane est géré via le gem [Gretel](https://github.com/lassebunk/gretel).
|
|
|
|
La configuration se fait via le fichier config/breadcrumbs.rb. |