From 91119bf54edc47429fb357cb70f47d61d1eba12d Mon Sep 17 00:00:00 2001 From: did Date: Wed, 1 Jun 2011 23:43:12 +0200 Subject: [PATCH] allow administrators to change the text displayed for each content in the back-office (documentation is coming) --- app/helpers/admin/content_types_helper.rb | 21 ++++++- app/helpers/admin/custom_fields_helper.rb | 4 +- app/models/content_type.rb | 7 ++- .../extensions/content_type/item_template.rb | 57 +++++++++++++++++++ app/models/extensions/page/parse.rb | 4 +- app/views/admin/content_types/_form.html.haml | 4 ++ app/views/admin/contents/_list.html.haml | 2 +- config/assets.yml | 1 + config/locales/default.de.yml | 7 ++- config/locales/default.en.yml | 6 +- config/locales/default.fr.yml | 6 +- config/locales/default.it.yml | 10 ++-- config/locales/default.pt-BR.yml | 6 +- config/locales/formtastic.en.yml | 2 + config/locales/formtastic.fr.yml | 2 + lib/locomotive/liquid/drops/content.rb | 2 +- public/javascripts/admin/application.js | 2 +- .../stylesheets/admin/formtastic_changes.css | 12 ++++ 18 files changed, 134 insertions(+), 21 deletions(-) create mode 100644 app/models/extensions/content_type/item_template.rb diff --git a/app/helpers/admin/content_types_helper.rb b/app/helpers/admin/content_types_helper.rb index e59d06bc..b9d7fca0 100644 --- a/app/helpers/admin/content_types_helper.rb +++ b/app/helpers/admin/content_types_helper.rb @@ -7,7 +7,7 @@ module Admin::ContentTypesHelper @content_types = current_site.content_types.ordered. limit(:contents => Locomotive.config.lastest_items_nb). - only(:name, :slug, :highlighted_field_name, :content_custom_fields_version, :order_by).to_a + only(:name, :slug, :highlighted_field_name, :content_custom_fields_version, :order_by, :serialized_item_template).to_a if @content_type && @content_type.persisted? && @content_types.index(@content_type) >= MAX_DISPLAYED_CONTENTS @content_types.delete(@content_type) @@ -67,4 +67,23 @@ module Admin::ContentTypesHelper end end + def content_label_for(content) + if content._parent.item_template.nil? + content._label # default one + else + assigns = { + 'site' => current_site, + 'content' => content.to_liquid + } + + registers = { + :controller => self, + :site => current_site, + :current_admin => current_admin + } + + preserve(content._parent.item_template.render(::Liquid::Context.new({}, assigns, registers))) + end + end + end \ No newline at end of file diff --git a/app/helpers/admin/custom_fields_helper.rb b/app/helpers/admin/custom_fields_helper.rb index 2c8a9d2f..e5705f05 100644 --- a/app/helpers/admin/custom_fields_helper.rb +++ b/app/helpers/admin/custom_fields_helper.rb @@ -40,7 +40,9 @@ module Admin::CustomFieldsHelper end def options_for_association_target - current_site.content_types.collect { |c| [c.name, c.content_klass.to_s] } + current_site.content_types.collect do |c| + c.persisted? ? [c.name, c.content_klass.to_s] : nil + end.compact end def options_for_has_one(field) diff --git a/app/models/content_type.rb b/app/models/content_type.rb index 77ba8c2a..c7330f2e 100644 --- a/app/models/content_type.rb +++ b/app/models/content_type.rb @@ -2,6 +2,9 @@ class ContentType include Locomotive::Mongoid::Document + ## extensions ## + include Extensions::ContentType::ItemTemplate + ## fields ## field :name field :description @@ -18,7 +21,7 @@ class ContentType embeds_many :contents, :class_name => 'ContentInstance', :validate => false do def visible @target.find_all { |c| c.visible? } - end + end end ## named scopes ## @@ -69,7 +72,7 @@ class ContentType self.ordered_contents end end - + def latest_updated_contents self.contents.latest_updated.reject { |c| !c.persisted? } end diff --git a/app/models/extensions/content_type/item_template.rb b/app/models/extensions/content_type/item_template.rb new file mode 100644 index 00000000..46ac8253 --- /dev/null +++ b/app/models/extensions/content_type/item_template.rb @@ -0,0 +1,57 @@ +module Extensions + module ContentType + module ItemTemplate + + extend ActiveSupport::Concern + + included do + field :raw_item_template + field :serialized_item_template, :type => Binary + + before_validation :serialize_item_template + + validate :item_template_must_be_valid + end + + module InstanceMethods + + def item_template + @item_template ||= Marshal.load(read_attribute(:serialized_item_template).to_s) rescue nil + end + + protected + + def serialize_item_template + if self.new_record? || self.raw_item_template_changed? + @item_parsing_errors = [] + + begin + self._parse_and_serialize_item_template + rescue ::Liquid::SyntaxError => error + @item_parsing_errors << I18n.t(:liquid_syntax, :error => error.to_s, :scope => [:errors, :messages]) + end + end + end + + def _parse_and_serialize_item_template + item_template = ::Liquid::Template.parse(self.raw_item_template, {}) + self.serialized_item_template = BSON::Binary.new(Marshal.dump(item_template)) + end + + def item_template_must_be_valid + @item_parsing_errors.try(:each) { |msg| self.errors.add :item_template, msg } + end + + # def item_template + # self.read_attribute(:default_item_template) || self.default_item_template + # end + # + # def default_item_template + # '{{ content.highlighted_field_value }}' + # end + + end + + end + end +end \ No newline at end of file diff --git a/app/models/extensions/page/parse.rb b/app/models/extensions/page/parse.rb index 4558b7dc..14b47b33 100644 --- a/app/models/extensions/page/parse.rb +++ b/app/models/extensions/page/parse.rb @@ -36,9 +36,9 @@ module Extensions begin self._parse_and_serialize_template rescue ::Liquid::SyntaxError => error - @parsing_errors << I18n.t(:liquid_syntax, :fullpath => self.fullpath, :error => error.to_s,:scope => [:errors, :messages]) + @parsing_errors << I18n.t(:liquid_syntax, :fullpath => self.fullpath, :error => error.to_s, :scope => [:errors, :messages, :page]) rescue ::Locomotive::Liquid::PageNotFound => error - @parsing_errors << I18n.t(:liquid_extend, :fullpath => self.fullpath,:scope => [:errors, :messages]) + @parsing_errors << I18n.t(:liquid_extend, :fullpath => self.fullpath, :scope => [:errors, :messages, :page]) end end end diff --git a/app/views/admin/content_types/_form.html.haml b/app/views/admin/content_types/_form.html.haml index abedb391..c4200675 100644 --- a/app/views/admin/content_types/_form.html.haml +++ b/app/views/admin/content_types/_form.html.haml @@ -13,6 +13,10 @@ = f.foldable_inputs :name => :presentation, :class => 'switchable' do = f.input :highlighted_field_name, :as => :select, :collection => options_for_highlighted_field(f.object, 'contents'), :include_blank => false = f.input :group_by_field_name, :as => :select, :collection => options_for_group_by_field(f.object, 'contents') + = f.custom_input :raw_item_template, :css => 'small-code' do + %code{ :class => 'html' } + = f.text_area :raw_item_template, :class => 'small' + = f.errors_on :item_template = f.foldable_inputs :name => :options, :class => 'switchable' do = f.input :order_by, :as => :select, :collection => options_for_order_by(f.object, 'contents'), :include_blank => false diff --git a/app/views/admin/contents/_list.html.haml b/app/views/admin/contents/_list.html.haml index c70c27f1..573ddd5c 100644 --- a/app/views/admin/contents/_list.html.haml +++ b/app/views/admin/contents/_list.html.haml @@ -6,7 +6,7 @@ %li.content{ :id => "content-#{content._id}" } %em %strong - = link_to content.send(@content_type.highlighted_field_name), edit_admin_content_path(@content_type.slug, content) + = link_to content_label_for(content), edit_admin_content_path(@content_type.slug, content) .more %span != t('admin.contents.index.updated_at') diff --git a/config/assets.yml b/config/assets.yml index 08194ecd..606b23fb 100644 --- a/config/assets.yml +++ b/config/assets.yml @@ -49,6 +49,7 @@ javascripts: - public/javascripts/admin/plugins/tiny_mce/tinymce.js - public/javascripts/admin/contents.js content_types: + - public/javascripts/admin/plugins/codemirror/codemirror.min.js - public/javascripts/admin/content_types.js site: - public/javascripts/admin/site.js diff --git a/config/locales/default.de.yml b/config/locales/default.de.yml index fc25397a..00b80140 100644 --- a/config/locales/default.de.yml +++ b/config/locales/default.de.yml @@ -32,9 +32,12 @@ de: protected_page: "Du kannst keine Index oder 404 Seiten löschen" extname_changed: "Die neue Datei hat nicht die originale Dateiendung" array_too_short: "ist zu kurz (minimale Element-Zahl ist %{count})" - liquid_syntax: "Liquid Syntax-Fehler, bitte überprüfe die Syntax ('%{error}'/'%{fullpath}')" - liquid_extend: "Die Seite '%{fullpath}' verwendet eine Vorlage, die gar nicht existiert" + liquid_syntax: "Liquid Syntax-Fehler, bitte überprüfe die Syntax ('%{error}')" invalid_theme_file: "darf nicht leer sein oder ist keine zip-Datei" + page: + liquid_syntax: "Liquid Syntax-Fehler, bitte überprüfe die Syntax ('%{error}'/'%{fullpath}')" + liquid_extend: "Die Seite '%{fullpath}' verwendet eine Vorlage, die gar nicht existiert" + attributes: defaults: diff --git a/config/locales/default.en.yml b/config/locales/default.en.yml index 9793b90e..06bc6631 100644 --- a/config/locales/default.en.yml +++ b/config/locales/default.en.yml @@ -11,9 +11,11 @@ en: protected_page: "You can not remove index or 404 pages" extname_changed: "New file does not have the original extension" array_too_short: "is too small (minimum element number is %{count})" - liquid_syntax: "Liquid Syntax error ('%{error}' on '%{fullpath}')" - liquid_extend: "The page '%{fullpath}' extends a template which does not exist" + liquid_syntax: "Liquid Syntax error ('%{error}')" invalid_theme_file: "can't be blank or isn't a zip file" + page: + liquid_syntax: "Liquid Syntax error ('%{error}' on '%{fullpath}')" + liquid_extend: "The page '%{fullpath}' extends a template which does not exist" attributes: defaults: diff --git a/config/locales/default.fr.yml b/config/locales/default.fr.yml index 9ec2aef7..5fcf7a37 100644 --- a/config/locales/default.fr.yml +++ b/config/locales/default.fr.yml @@ -32,9 +32,11 @@ fr: protected_page: "Vous ne pouvez pas supprimer les pages index et 404" extname_changed: "Nouveau fichier n'a pas l'extension original" array_too_short: "est trop petit (le nombre minimum d'éléments est %{count})" - liquid_syntax: "Erreur de syntaxe dans les sections de page, veuillez vérifier la syntaxe ('%{error}'/'%{fullpath}')" - liquid_extend: "La page '%{fullpath}' étend le contenu d'une page qui n'existe pas" + liquid_syntax: "Erreur de syntaxe ('%{error}')" invalid_theme_file: "doit être rempli ou n'est pas un fichier zip" + page: + liquid_syntax: "Erreur de syntaxe dans les sections de page, veuillez vérifier la syntaxe ('%{error}'/'%{fullpath}')" + liquid_extend: "La page '%{fullpath}' étend le contenu d'une page qui n'existe pas" attributes: defaults: diff --git a/config/locales/default.it.yml b/config/locales/default.it.yml index a4ecfb75..8fc0f581 100644 --- a/config/locales/default.it.yml +++ b/config/locales/default.it.yml @@ -38,9 +38,11 @@ it: protected_page: "Non è possibile eliminare le pagine index e 404" extname_changed: "Il nuovo file non ha l'estesione originale" array_too_short: "troppo corto (il numero minimo di elementi è %{count})" - liquid_syntax: "Errore nella sintassi Liquid ('%{error}' in '%{fullpath}')" - liquid_extend: "La pagina '%{fullpath}' estende un template che non esiste" + liquid_syntax: "Errore nella sintassi Liquid ('%{error}')" invalid_theme_file: "non può essere vuoto o non è un file zip" + page: + liquid_syntax: "Errore nella sintassi Liquid ('%{error}' in '%{fullpath}')" + liquid_extend: "La pagina '%{fullpath}' estende un template che non esiste" attributes: defaults: @@ -110,7 +112,7 @@ it: pagination: previous: "« Precedente" next: "Successiva »" - + date: formats: default: "%d/%m/%Y" @@ -242,4 +244,4 @@ it: skip_last_comma: true words_connector: ", " two_words_connector: " e " - last_word_connector: " e " \ No newline at end of file + last_word_connector: " e " \ No newline at end of file diff --git a/config/locales/default.pt-BR.yml b/config/locales/default.pt-BR.yml index e8966e61..7a8da224 100644 --- a/config/locales/default.pt-BR.yml +++ b/config/locales/default.pt-BR.yml @@ -30,9 +30,11 @@ pt-BR: protected_page: "Você não pode remover a página inicial e a do erro 404" extname_changed: "Novo arquivos não tem a mesma extensão que o original" array_too_short: "é muito pequeno (mínimo de elementos é %{count})" - liquid_syntax: "Erro de sintaxe do Liquid, por favor verifique a sintaxe" - liquid_extend: "A página extende um template que não existe." + liquid_syntax: "Erro de sintaxe do Liquid, por favor verifique a sintaxe ('%{error}')" invalid_theme_file: "não pode ser vazio ou não é um arquivo zip" + page: + liquid_syntax: "Erro de sintaxe do Liquid, por favor verifique a sintaxe" + liquid_extend: "A página extende um template que não existe." date: diff --git a/config/locales/formtastic.en.yml b/config/locales/formtastic.en.yml index 0738c3c2..8dafb198 100644 --- a/config/locales/formtastic.en.yml +++ b/config/locales/formtastic.en.yml @@ -38,6 +38,7 @@ en: reset: Reset site default_site_template: "Use the default site template. Click here to upload a site template as a zip file instead." content_type: + raw_item_template: Item template api_accounts: Notified Accounts account: edit: @@ -78,6 +79,7 @@ en: samples: "If enabled, the import process will also copy contents and assets" reset: "If enabled, all the data of your site will be destroyed before importing the new site" content_type: + raw_item_template: "You can customize the text displayed for each item in the list. Simply use Liquid. Ex: {{ content.name }})" api_enabled: "It is used to let people from outside to create new instances (example: messages in a contact form)" api_accounts: "A notification email will be sent to each of the accounts listed above when a new instance is created" diff --git a/config/locales/formtastic.fr.yml b/config/locales/formtastic.fr.yml index 99e98bf6..c57acd0c 100644 --- a/config/locales/formtastic.fr.yml +++ b/config/locales/formtastic.fr.yml @@ -40,6 +40,7 @@ fr: samples: Copier contenu reset: Remettre à zéro content_type: + raw_item_template: Template d'affichage api_accounts: Comptes à notifier account: edit: @@ -81,5 +82,6 @@ fr: reset: "Si activé, toutes les données de votre site seront détruites avant l'import du nouveau site" content_type: slug: Nom utilisé dans les templates liquid afin d'accéder aux enregistrements de ce modèle + raw_item_template: "Personnaliser le texte affiché pour chaque élément de la liste. Utilisez simplement du code Liquid. Ex: {{ content.name }}" api_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" diff --git a/lib/locomotive/liquid/drops/content.rb b/lib/locomotive/liquid/drops/content.rb index 5aafcf75..58613178 100644 --- a/lib/locomotive/liquid/drops/content.rb +++ b/lib/locomotive/liquid/drops/content.rb @@ -2,7 +2,7 @@ module Locomotive module Liquid module Drops class Content < Base - delegate :meta_keywords, :meta_description, :to => "@source" + delegate :meta_keywords, :meta_description, :to => '@source' def before_method(meth) return '' if @source.nil? diff --git a/public/javascripts/admin/application.js b/public/javascripts/admin/application.js index 00093fed..5c789ccd 100644 --- a/public/javascripts/admin/application.js +++ b/public/javascripts/admin/application.js @@ -22,7 +22,7 @@ var addCodeMirrorEditor = function(type, el, parser) { parser = (parser || 'Liquid') + 'Parser'; var editor = CodeMirror.fromTextArea(el.attr('id'), { - height: "400px", + height: el.hasClass('small') ? '60px' : '400px', stylesheet: [ "/stylesheets/admin/plugins/codemirror/csscolors.css", "/stylesheets/admin/plugins/codemirror/xmlcolors.css", diff --git a/public/stylesheets/admin/formtastic_changes.css b/public/stylesheets/admin/formtastic_changes.css index 44f279cb..e1b1c65e 100644 --- a/public/stylesheets/admin/formtastic_changes.css +++ b/public/stylesheets/admin/formtastic_changes.css @@ -144,6 +144,18 @@ form.formtastic fieldset ol li.code p.inline-errors { background-image: none; } +form.formtastic fieldset ol li.small-code code { margin: 0px; display: inline-block; width: 75%; } +form.formtastic fieldset ol li.small-code p.inline-errors { + position: relative; + display: block !important; + float: none; + margin-left: 20%; + width: 45%; + margin: 0.5em 0px 0px 20%; + left: 0px; +} + + form.formtastic fieldset ol .more { text-align: right; width: auto; margin: 10px 20px 0 0; line-height: 0.6em; } form.formtastic fieldset ol .more a { text-decoration: none; color: #787A89; font-size: 0.7em; } form.formtastic fieldset ol .more a:hover { text-decoration: underline; }