it is now possible to change the response type of a page + correct translations in French

This commit is contained in:
Didier Lafforgue 2012-03-22 19:20:31 +01:00
parent 6b8e3db8c3
commit a9aeffba9b
15 changed files with 126 additions and 50 deletions

View File

@ -16,7 +16,7 @@ class Locomotive.Models.Page extends Backbone.Model
toJSON: -> toJSON: ->
_.tap super, (hash) => _.tap super, (hash) =>
_.each ['content_type_id_text', 'edit_url', 'parent_id_text'], (key) => delete hash[key] _.each ['content_type_id_text', 'edit_url', 'parent_id_text', 'response_type_text'], (key) => delete hash[key]
delete hash['editable_elements'] delete hash['editable_elements']
hash.editable_elements = @get('editable_elements').toJSONForSave() if @get('editable_elements')? && @get('editable_elements').length > 0 hash.editable_elements = @get('editable_elements').toJSONForSave() if @get('editable_elements')? && @get('editable_elements').length > 0

View File

@ -37,6 +37,9 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
# the url gets modified by different ways so reflect the changes in the UI # the url gets modified by different ways so reflect the changes in the UI
@listen_for_url_changes() @listen_for_url_changes()
# enable response type
@enable_response_type_select()
# enable check boxes # enable check boxes
@enable_templatized_checkbox() @enable_templatized_checkbox()
@ -110,6 +113,14 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
success: (data) => success: (data) =>
@$('#page_slug_input .inline-hints').html(data.url).effect('highlight') @$('#page_slug_input .inline-hints').html(data.url).effect('highlight')
enable_response_type_select: ->
@$('li#page_response_type_input').change (event) =>
if $(event.target).val() == 'text/html'
@$('li#page_redirect_input, li#page_redirect_url_input').show()
else
@model.set redirect: false
@$('li#page_redirect_input, li#page_redirect_url_input').hide()
enable_templatized_checkbox: -> enable_templatized_checkbox: ->
@_enable_checkbox 'templatized', @_enable_checkbox 'templatized',
features: ['slug', 'redirect', 'listed'] features: ['slug', 'redirect', 'listed']

View File

@ -80,6 +80,7 @@ ul.list {
span.untranslated { span.untranslated {
@include label; @include label;
background-color: #F89406;
top: -1px; top: -1px;
left: 5px; left: 5px;
} }
@ -219,6 +220,13 @@ ul.list {
&.hidden a { font-style: italic; font-weight: normal; } &.hidden a { font-style: italic; font-weight: normal; }
span.untranslated { span.untranslated {
@include label;
background-color: #F89406;
top: 3px;
left: 5px;
}
span.response-type {
@include label; @include label;
top: 3px; top: 3px;
left: 5px; left: 5px;

View File

@ -50,5 +50,18 @@ module Locomotive
] ]
end end
def options_for_page_response_type
[
['HTML', 'text/html'],
['RSS', 'application/rss+xml'],
['XML', 'text/xml'],
['JSON', 'application/json']
]
end
def page_response_type_to_string(page)
options_for_page_response_type.detect { |t| t.last == page.response_type }.try(:first) || '—'
end
end end
end end

View File

@ -22,6 +22,7 @@ module Locomotive
field :locales, :type => Array field :locales, :type => Array
field :published, :type => Boolean, :default => false field :published, :type => Boolean, :default => false
field :cache_strategy, :default => 'none' field :cache_strategy, :default => 'none'
field :response_type, :default => 'text/html'
## associations ## ## associations ##
belongs_to :site, :class_name => 'Locomotive::Site' belongs_to :site, :class_name => 'Locomotive::Site'
@ -51,7 +52,7 @@ module Locomotive
scope :published, :where => { :published => true } scope :published, :where => { :published => true }
scope :fullpath, lambda { |fullpath| { :where => { :fullpath => fullpath } } } scope :fullpath, lambda { |fullpath| { :where => { :fullpath => fullpath } } }
scope :handle, lambda { |handle| { :where => { :handle => handle } } } scope :handle, lambda { |handle| { :where => { :handle => handle } } }
scope :minimal_attributes, lambda { |attrs = []| { :only => (attrs || []) + %w(title slug fullpath position depth published templatized redirect listed parent_id site_id created_at updated_at) } } scope :minimal_attributes, lambda { |attrs = []| { :only => (attrs || []) + %w(title slug fullpath position depth published templatized redirect listed response_type parent_id site_id created_at updated_at) } }
scope :dependent_from, lambda { |id| { :where => { :template_dependencies.in => [id] } } } scope :dependent_from, lambda { |id| { :where => { :template_dependencies.in => [id] } } }
## methods ## ## methods ##
@ -72,6 +73,10 @@ module Locomotive
self.cache_strategy != 'none' self.cache_strategy != 'none'
end end
def default_response_type?
self.response_type == 'text/html'
end
def translated? def translated?
self.title_translations.key?(::Mongoid::Fields::I18n.locale.to_s) rescue false self.title_translations.key?(::Mongoid::Fields::I18n.locale.to_s) rescue false
end end

View File

@ -1,7 +1,7 @@
module Locomotive module Locomotive
class PagePresenter < BasePresenter class PagePresenter < BasePresenter
delegate :title, :slug, :fullpath, :handle, :raw_template, :published, :listed, :templatized, :redirect, :redirect_url, :template_changed, :cache_strategy, :to => :source delegate :title, :slug, :fullpath, :handle, :raw_template, :published, :listed, :templatized, :redirect, :redirect_url, :template_changed, :cache_strategy, :response_type, :to => :source
def escaped_raw_template def escaped_raw_template
h(self.source.raw_template) h(self.source.raw_template)
@ -12,7 +12,7 @@ module Locomotive
end end
def included_methods def included_methods
super + %w(title slug fullpath handle raw_template published listed templatized redirect redirect_url cache_strategy template_changed editable_elements localized_fullpaths) super + %w(title slug fullpath handle raw_template published listed templatized redirect redirect_url cache_strategy response_type template_changed editable_elements localized_fullpaths)
end end
def localized_fullpaths def localized_fullpaths

View File

@ -32,6 +32,8 @@
= f.input :handle = f.input :handle
= f.input :response_type, :as => :select, :collection => options_for_page_response_type, :include_blank => false
= f.input :templatized, :as => :'Locomotive::Toggle', :style => "#{'display: none' if @page.redirect?}" = f.input :templatized, :as => :'Locomotive::Toggle', :style => "#{'display: none' if @page.redirect?}"
= f.input :target_klass_name, :as => :select, :collection => options_for_target_klass_name, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}" } = f.input :target_klass_name, :as => :select, :collection => options_for_target_klass_name, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}" }
@ -40,7 +42,7 @@
= f.input :listed, :as => :'Locomotive::Toggle' = f.input :listed, :as => :'Locomotive::Toggle'
= f.input :redirect, :as => :'Locomotive::Toggle', :style => "#{'display: none' if @page.templatized?}" = f.input :redirect, :as => :'Locomotive::Toggle', :wrapper_html => { :style => "#{'display: none' if @page.templatized? || !@page.default_response_type?}" }
= f.input :cache_strategy, :as => :select, :collection => options_for_page_cache_strategy, :include_blank => false, :wrapper_html => { :style => "#{'display: none' if @page.redirect?}" } = f.input :cache_strategy, :as => :select, :collection => options_for_page_cache_strategy, :include_blank => false, :wrapper_html => { :style => "#{'display: none' if @page.redirect?}" }

View File

@ -17,6 +17,9 @@
= link_to truncate(page.title, :length => 80), edit_page_url(page) = link_to truncate(page.title, :length => 80), edit_page_url(page)
- unless page.default_response_type?
%span.response-type= page_response_type_to_string(page)
- unless page.translated? - unless page.translated?
%span.untranslated= t('locomotive.shared.list.untranslated') %span.untranslated= t('locomotive.shared.list.untranslated')

View File

@ -77,10 +77,17 @@ fr:
file: file:
delete_file: Supprimer fichier delete_file: Supprimer fichier
has_many: has_many:
empty: Vide empty: La liste est vide
new_entry: + Ajouter une nouvelle entrée
many_to_many:
empty: La liste est vide. Ajouter une entrée depuis la liste ci-dessous.
form: form:
is_required: est obligatoire required: Required
default_label: Nom du champ optional: Optional
default_label: Field name
select_options:
ask_name: "Type the label of the option"
sessions: sessions:
new: new:
@ -149,6 +156,8 @@ fr:
new: new:
title: "Nouveau site" title: "Nouveau site"
help: "Remplissez le formulaire ci-dessous pour créer votre nouveau site." help: "Remplissez le formulaire ci-dessous pour créer votre nouveau site."
domains:
empty: Aucun domaine
current_site: current_site:
edit: edit:
@ -187,6 +196,7 @@ fr:
media: Média media: Média
fonts: Polices fonts: Polices
no_items: "Il n'existe pas de fichiers." no_items: "Il n'existe pas de fichiers."
quick_upload: "Upload rapide"
asset: asset:
updated_at: Mis à jour le updated_at: Mis à jour le
new: new:
@ -216,6 +226,7 @@ fr:
content_types: content_types:
index: index:
new: nouveau modèle new: nouveau modèle
edit: éditer
new: new:
title: Nouveau modèle title: Nouveau modèle
help: "Créer votre propre modèle de données (Projets, Personnes, ...etc). Votre modèle doit au moins comporter un champ. Le premier champ sera obligatoire lorsque vous ajouterez un élément de ce type-là." help: "Créer votre propre modèle de données (Projets, Personnes, ...etc). Votre modèle doit au moins comporter un champ. Le premier champ sera obligatoire lorsque vous ajouterez un élément de ce type-là."

View File

@ -52,7 +52,7 @@ fr:
mongoid: mongoid:
attributes: attributes:
page: locomotive/page:
title: Titre title: Titre
parent: Dossier parent parent: Dossier parent
parent_id: Dossier parent parent_id: Dossier parent
@ -63,42 +63,49 @@ fr:
redirect: Redirection redirect: Redirection
redirect_url: Url de redirection redirect_url: Url de redirection
cache_strategy: Cache cache_strategy: Cache
response_type: Type de réponse
seo_title: Titre SEO seo_title: Titre SEO
content_type: locomotive/content_type:
name: Nom name: Nom
description: Description description: Description
slug: Raccourci slug: Raccourci
order_by: Ordonner order_by: Ordonner
highlighted_field_name: Champ mis en avant order_direction: Direction
label_field_name: Champ mis en avant
label_field_id: Champ mis en avant
group_by_field_name: Champ pour grouper group_by_field_name: Champ pour grouper
api_enabled: Activation API group_by_field_id: Champ pour grouper
asset: public_submission_enabled: Activation API
public_submission_accounts: Comptes à notifier
locomotive/asset:
source: Fichier source: Fichier
account: locomotive/account:
email: E-mail email: E-mail
name: Nom name: Nom
language: Langue language: Langue
password: Mot de passe password: Mot de passe
password_confirmation: Confirmation mot de passe password_confirmation: Confirmation mot de passe
snippet: locomotive/snippet:
body: Code body: Code
slug: Raccourci slug: Raccourci
name: Nom name: Nom
theme_asset: locomotive/theme_asset:
content_type: Type du fichier content_type: Type du fichier
site: locomotive/site:
name: Nom du site name: Nom du site
locales: Langues
domain_name: Domaine domain_name: Domaine
subdomain: Sous-domaine subdomain: Sous-domaine
restricted_access: Activer ? restricted_access: Activer ?
access_login: Identifiant access_login: Identifiant
access_password: "Mot de passe" access_password: "Mot de passe"
custom_fields: custom_fields/field:
field: name: Alias
name: Alias hint: Aide
hint: Aide required: Requis ?
required: Requis ? text_formatting: Formattage
text_formatting: Formattage localized: Localisé ?
select_options: Options
pagination: pagination:
previous: "&laquo; Précédent" previous: "&laquo; Précédent"

View File

@ -33,12 +33,6 @@ en:
custom_fields: custom_fields:
field: field:
name: Alias name: Alias
import:
new:
source: File
samples: Copy samples
reset: Reset site
default_site_template: "Use the default site template. Click <a href='#'>here</a> to upload a site template as a zip file instead."
content_type: content_type:
raw_item_template: Item template raw_item_template: Item template
public_submission_enabled: Public submission public_submission_enabled: Public submission

View File

@ -35,13 +35,8 @@ fr:
custom_fields: custom_fields:
field: field:
name: Alias name: Alias
import:
new:
source: Fichier
samples: Copier contenu
reset: Remettre à zéro
content_type: content_type:
item_template: Template d'affichage raw_item_template: Template d'affichage
api_accounts: Comptes à notifier api_accounts: Comptes à notifier
content_entry: content_entry:
_slug: Permalink _slug: Permalink
@ -51,6 +46,7 @@ fr:
password: Nouveau mot de passe password: Nouveau mot de passe
password_confirmation: Confirmation nouveau mot de passe password_confirmation: Confirmation nouveau mot de passe
page: page:
target_klass_name: Modèle
seo_title: Titre seo_title: Titre
hints: hints:
@ -59,13 +55,14 @@ fr:
cache_strategy: "Cache la page pour de meilleure performance. L'option 'Simple' est le meilleur compromis." cache_strategy: "Cache la page pour de meilleure performance. L'option 'Simple' est le meilleur compromis."
templatized: "Utilise la page comme un template pour un modèle défini." templatized: "Utilise la page comme un template pour un modèle défini."
listed: "Controle si la page doit être visible depuis les menus automatiquement générés." listed: "Controle si la page doit être visible depuis les menus automatiquement générés."
content_type_id: "Le type du contenu pour lequel cette page est un template." target_klass_name: "Le type du contenu pour lequel cette page est un template."
seo_title: "Définit un titre de page à mettre dans la balise TITLE de la page. Laissez le blanc pour utiliser la valeur par défaut (voir configuration du site)." seo_title: "Définit un titre de page à mettre dans la balise TITLE de la page. Laissez le blanc pour utiliser la valeur par défaut (voir configuration du site)."
meta_keywords: "Redéfinit les mots-clés du site. Utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule." meta_keywords: "Redéfinit les mots-clés du site. Utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule."
meta_description: "Redéfinit la description du site. Utilisée à l'intérieur de la balise HEAD." meta_description: "Redéfinit la description du site. Utilisée à l'intérieur de la balise HEAD."
snippet: snippet:
slug: "Utilisé pour insérer le snippet dans une page." slug: "Utilisé pour insérer le snippet dans une page."
site: site:
seo_title: "Valeur globale qui sera utilisée par défaut dans la balise TITLE de la section HEAD. Requis pour un meilleur référencement."
meta_keywords: "Mots-clés utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule. Requis pour un meilleur référencement." meta_keywords: "Mots-clés utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule. Requis pour un meilleur référencement."
meta_description: "Description utilisée à l'intérieur de la balise HEAD. Requis pour un meilleur référencement." meta_description: "Description utilisée à l'intérieur de la balise HEAD. Requis pour un meilleur référencement."
domain_name: "ex: locomotiveapp.org" domain_name: "ex: locomotiveapp.org"
@ -88,12 +85,8 @@ fr:
seo_title: "La valeur que vous rentrez sera utilisée comme titre SEO pour la page faisant office de template pour ce modèle." seo_title: "La valeur que vous rentrez sera utilisée comme titre SEO pour la page faisant office de template pour ce modèle."
meta_keywords: "Redéfinit les mots-clés du site. Utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule." meta_keywords: "Redéfinit les mots-clés du site. Utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule."
meta_description: "Redéfinit la description du site. Utilisée à l'intérieur de la balise HEAD." meta_description: "Redéfinit la description du site. Utilisée à l'intérieur de la balise HEAD."
import:
source: "Un fichier zip contenant database.yml, les fichiers du thème et les templates de page"
samples: "Si activé, les contenus et les média seront aussi copiés lors de l'import"
reset: "Si activé, toutes les données de votre site seront détruites avant l'import du nouveau site"
content_type: content_type:
slug: Nom utilisé dans les templates liquid afin d'accéder aux enregistrements de ce modèle slug: Nom utilisé dans les templates liquid afin d'accéder aux enregistrements de ce modèle
item_template: "Personnaliser le texte affiché pour chaque élément de la liste. Utilisez simplement du code Liquid. Ex: {{ entry.name }}" raw_item_template: "Personnaliser le texte affiché pour chaque élément de la liste. Utilisez simplement du code Liquid. Ex: {{ entry.name }}"
api_enabled: "Utilisé pour autoriser la création de nouvelles instances de l'extérieur (ex.: les messages dans un formulaire de contact)" public_submission_enabled: "Utilisé pour autoriser la création de nouvelles instances de l'extérieur (ex.: les messages dans un formulaire de contact)"
api_accounts: "Un email de notification sera envoyé à chaque compte listé ci-dessus lors de la création d'une nouvelle instance" public_submission_accounts: "Un email de notification sera envoyé à chaque compte listé ci-dessus lors de la création d'une nouvelle instance"

View File

@ -26,20 +26,25 @@ module Locomotive
end end
def locomotive_page def locomotive_page
page = nil
path = self.locomotive_page_path path = self.locomotive_page_path
if page = current_site.pages.any_in(:fullpath => [*path]).first current_site.pages.any_in(:fullpath => [*path]).each do |_page|
if not page.published? and current_locomotive_account.nil? if not _page.published? and current_locomotive_account.nil?
page = nil next
else else
if page.templatized? if _page.templatized?
@content_entry = page.fetch_target_entry(File.basename(path.first)) @content_entry = _page.fetch_target_entry(File.basename(path.first))
if @content_entry.nil? || (!@content_entry.visible? && current_locomotive_account.nil?) # content instance not found or not visible if @content_entry.nil? || (!@content_entry.visible? && current_locomotive_account.nil?) # content instance not found or not visible
page = nil next
end end
end end
end end
page = _page
break
end end
page || not_found_page page || not_found_page
@ -101,7 +106,7 @@ module Locomotive
def prepare_and_set_response(output) def prepare_and_set_response(output)
flash.discard flash.discard
response.headers['Content-Type'] = 'text/html; charset=utf-8' response.headers['Content-Type'] = "#{@page.response_type}; charset=utf-8"
response.headers['Editable'] = 'true' unless self.editing_page? || current_locomotive_account.nil? response.headers['Editable'] = 'true' unless self.editing_page? || current_locomotive_account.nil?
if @page.with_cache? if @page.with_cache?

View File

@ -37,6 +37,12 @@ describe 'Locomotive rendering system' do
@controller.response.headers['Content-Type'].should == 'text/html; charset=utf-8' @controller.response.headers['Content-Type'].should == 'text/html; charset=utf-8'
end end
it 'sets the content type to the one specified by the page' do
@page.response_type = 'application/json'
@controller.send(:prepare_and_set_response, 'Hello world !')
@controller.response.headers['Content-Type'].should == 'application/json; charset=utf-8'
end
it 'sets the status to 200 OK' do it 'sets the status to 200 OK' do
@controller.status.should == :ok @controller.status.should == :ok
end end

View File

@ -307,6 +307,24 @@ describe Locomotive::Page do
end end
end end
describe 'response type' do
before(:each) do
@page = FactoryGirl.build(:page, :site => nil)
end
it 'is a HTML document by default' do
@page.response_type.should == 'text/html'
@page.default_response_type?.should be_true
end
it 'can also be a JSON document' do
@page.response_type = 'application/json'
@page.default_response_type?.should be_false
end
end
class Foo class Foo
end end