Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Multilocale cms

commit 9bc3e360f5e4e1b597e921a537e64c8741ac579b
Author: pyromaniac <kinwizard@gmail.com>
Date:   Wed Sep 19 18:26:02 2012 +0700

    Fixed localized interface

commit 7c5c6ebd0d9514dde446b0a879c811df59aa8696
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Tue Aug 28 19:06:09 2012 +0800

    minor edits

commit a3b1f659f04fcd6c6d120dc7439bc1445a95306b
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Tue Aug 28 19:01:03 2012 +0800

    locale fallback and turning localization on/off

commit 156545c81686c7d1d8b9a535def3ce12675e5e89
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Mon Aug 27 17:38:55 2012 +0800

    ui support for disabled/enabled locales

commit fc2e4251d1102116b77a52161d55484112d6a2a9
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Thu Aug 23 22:13:31 2012 +0800

    page.all_inherited_page_parts rewritten to make all old specs pass

commit b844ea3f34ad1e12e97c8e1f86f44d04834a02b4
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Thu Aug 23 18:05:50 2012 +0800

    render only page parts of current locale

commit 9612ace8a48d9fbabf6325e94943780d1fba7166
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Wed Aug 22 21:23:28 2012 +0800

    completed js code for multilocale UI

commit a867abee464e1a82651319fa8f8626cae5611a2a
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Tue Aug 21 16:36:12 2012 +0800

    part with default locale added, restyled locale buttons, all locale removed with a part, a new locale added to a part

commit 736d4ef26851a4f28180eed40b2bd6afbcf7c7ca
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Mon Aug 20 16:47:30 2012 +0800

    minor changes

commit 7116b12fe35e748f09fabd8dfa4b6a705f94522f
Author: Andrew Gridnev <andrew.gridnev@gmail.com>
Date:   Mon Aug 20 16:42:18 2012 +0800

    multiple locales supported in page parts
  • Loading branch information...
commit 50f734402ce2caaa20fe330276c91ca3c5251407 1 parent 13dcef4
Arkadiy Zabazhanov pyromaniac authored
Showing with 540 additions and 93 deletions.
  1. +109 −29 app/assets/javascripts/puffer/puffer_pages.js
  2. +73 −0 app/assets/stylesheets/puffer/puffer_pages.css
  3. +6 −0 app/components/page_parts/_page_part.html.erb
  4. +18 −0 app/components/page_parts/_page_part_locales.html.erb
  5. +11 −25 app/components/page_parts/form.html.erb
  6. +8 −0 app/components/page_parts_component.rb
  7. +5 −0 db/migrate/20120817143224_add_locale_to_page_parts.rb
  8. +7 −0 lib/puffer_pages.rb
  9. +4 −3 lib/puffer_pages/backends/controllers/pages_base.rb
  10. +47 −6 lib/puffer_pages/backends/models/page.rb
  11. +11 −2 lib/puffer_pages/backends/models/page_part.rb
  12. +51 −0 lib/puffer_pages/liquid/tags/translate.rb
  13. +8 −2 puffer_pages.gemspec
  14. +6 −0 spec/dummy/app/controllers/application_controller.rb
  15. +3 −1 spec/dummy/config/application.rb
  16. +1 −1  spec/dummy/config/environments/development.rb
  17. +1 −0  spec/dummy/config/initializers/puffer_pages.rb
  18. +5 −0 spec/dummy/db/migrate/20120817143224_add_locale_to_page_parts.rb
  19. +2 −1  spec/dummy/db/schema.rb
  20. +1 −1  spec/integration/navigation_spec.rb
  21. +40 −0 spec/models/page_part_spec.rb
  22. +122 −21 spec/models/page_spec.rb
  23. +1 −1  spec/spec_helper.rb
138 app/assets/javascripts/puffer/puffer_pages.js
View
@@ -5,11 +5,10 @@
//= require puffer/codemirror/javascript
//= require puffer/codemirror/css
//= require_tree ./codemirror
-//= require puffer/liquid
Tabs.include({
- initialize: function(options) {
- this.$super(options);
+ initialize: function(element, options) {
+ this.$super(element, options);
this.buildAddButton();
},
@@ -17,6 +16,9 @@ Tabs.include({
if (isFunction(this.options.addButton)) {
this.addButton = $E('a', {'class': 'rui-tabs-tab rui-tabs-add', 'html': '<a href="#">+</a>'}).insertTo(this.tabsList);
this.addButton.onClick(this.options.addButton.bind(this));
+ this.onAdd(function(event) {
+ this.addButton.insertTo(this.tabsList);
+ });
}
},
@@ -42,37 +44,118 @@ Tabs.include({
}
});
+Tabs.Tab.include({
+ initialize: function(element, main) {
+ this.$super(element, main);
+ if (main.options.disablable) {
+ this.link.insert($E('div', {
+ 'class': 'rui-tabs-tab-close-icon', 'html': '&times;'
+ }).onClick(function(event) {
+ if (this.main.enabled().length > 1) {
+ if (this.current()) {
+ var enabled = this.main.enabled();
+ var sibling = enabled[enabled.indexOf(this) + 1] || enabled[enabled.indexOf(this)-1];
+
+ if (sibling) {
+ sibling.select();
+ }
+ }
+ this.disable();
+ }
+ event.stop();
+ }.bind(this)));
+ }
+ }
+});
+
var page_part_tab_select = function(event) {
+ var inner_tabs = event.target.panel.find('.rui-tabs,*[data-tabs]').first();
+ if (inner_tabs instanceof Tabs)
+ inner_tabs.current().select();
+
var textarea = event.target.panel.first('textarea[data-codemirror]');
- if (textarea.codemirror) {
+ if (textarea && textarea.codemirror) {
textarea.codemirror.refresh();
}
}
-var page_part_tab_remove = function(event) {
- var destroy_mark = event.target.panel.first('.destroy_mark');
- var page_part_param = destroy_mark.next();
- $('page_parts_marked_for_destroy').append(destroy_mark.value('1'))
- if (page_part_param) {
- $('page_parts_marked_for_destroy').append(page_part_param);
- }
-}
-
var page_part_tab_add = function(event) {
- event.stop();
- var new_id = new Date().getTime();
var _this = this;
+
new Dialog.Prompt({label: 'Enter new page part name'}).onOk(function() {
var value = this.input.value();
if (!value.blank()) {
- _this.add(value, new_page_part_tab_panel.replace(/new_page_part_tab_panel_index/g, new_id), {id: new_id});
- _this.tabs.last().panel.first('input[type=hidden]').value(value);
- _this.tabs.last().select();
- _this.addButton.insertTo(_this.tabsList);
- $$('textarea[data-codemirror]').each(init_codemirror);
+ _this.add(value);
+ var tab = _this.tabs.last();
+ tab.panel.data('name', value);
+ fill_new_tab(tab);
+ tab.select();
+
+ Tabs.rescan();
+ init_codemirrors();
this.hide();
}
}).show();
+ event.stop();
+}
+
+var page_part_tab_remove = function(event) {
+ save_destroy_marks(event.target.panel);
+}
+
+var page_part_locale_select = function(event) {
+ if (!event.target.enabled())
+ event.target.enable();
+ if (!event.target.current())
+ event.target.select();
+
+ if (event.target.panel.html().blank())
+ fill_new_tab(event.target);
+
+ var textarea = event.target.panel.first('textarea[data-codemirror]');
+ if (textarea && textarea.codemirror) {
+ textarea.codemirror.refresh();
+ }
+}
+
+var page_part_locale_enable = function(event) {
+ fill_new_tab(event.target);
+}
+
+var page_part_locale_disable = function(event) {
+ save_destroy_marks(event.target.panel);
+ event.target.panel.update();
+}
+
+var fill_new_tab = function(tab) {
+ var new_id = new Date().getTime();
+ if (tab.main.data('new-panel'))
+ tab.panel.update(tab.main.data('new-panel').replace(new RegExp(tab.main.data('new-panel-variable'), 'g'), new_id));
+
+ var name_input = tab.panel.first('[data-acts="name"]');
+ var name_panel = tab.panel.first().parent('[data-name]');
+ if (name_input && name_panel) {
+ name_input.value(name_panel.data('name'));
+ }
+
+ var locale_input = tab.panel.first('[data-acts="locale"]');
+ var locale = tab.data('locale');
+ if (locale_input && locale) {
+ locale_input.value(locale);
+ }
+
+ init_codemirrors();
+}
+
+var save_destroy_marks = function(scope) {
+ var form = scope.tab.main.parent('form');
+ scope.find('[data-acts="destroy"]').each(function(destroy_mark) {
+ var page_part_param = destroy_mark.siblings('[data-acts="id"]').first();
+ if (page_part_param) {
+ form.append(destroy_mark.value('true'));
+ form.append(page_part_param);
+ }
+ });
}
var init_codemirror = function(textarea) {
@@ -83,13 +166,6 @@ var init_codemirror = function(textarea) {
lineWrapping: true,
matchBrackets: true,
tabSize: 2,
- // onCursorActivity: function(editor) {
- // if (editor.last_active_line != undefined) {
- // editor.setLineClass(editor.last_active_line, null);
- // }
- // editor.last_active_line = editor.getCursor().line;
- // editor.setLineClass(editor.last_active_line, "active_line");
- // },
extraKeys: {
"Tab": "indentMore",
"Shift-Tab": "indentLess",
@@ -103,8 +179,12 @@ var init_codemirror = function(textarea) {
}
}
-$(document).onReady(function() {
+var init_codemirrors = function() {
$$('textarea[data-codemirror]').each(init_codemirror);
+}
+
+$(document).onReady(function() {
+ init_codemirrors();
});
$(document).on('data:sending', function() {
@@ -115,7 +195,7 @@ $(document).on('data:sending', function() {
$(document).on('ajax:complete', function() {
Tabs.rescan();
- $$('textarea[data-codemirror]').each(init_codemirror);
+ init_codemirrors();
});
"*[data-codemirror-button]".onClick(function(event) {
73 app/assets/stylesheets/puffer/puffer_pages.css
View
@@ -35,6 +35,26 @@ div.CodeMirror span.CodeMirror-matchingbracket
min-height: 300px;
}
+#page_parts .localized-tabs {
+ border: 0;
+}
+
+#page_parts .localized-tabs .rui-tabs-panel {
+ border: 0;
+}
+
+#page_parts .localized-tabs .rui-tabs-list {
+ border: 0;
+ z-index: 100;
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+
+#page_parts .localized-tabs .rui-tabs-tab a {
+ border: 0;
+}
+
.active_line {
background: #eee !important;
}
@@ -64,6 +84,59 @@ div.CodeMirror span.CodeMirror-matchingbracket
cursor: pointer;
}
+.codemirror_buttons li.locales-group-item,
+.codemirror_buttons li.selected-locales-group-item,
+.codemirror_buttons .unavailable-locales-group-item {
+ border-radius: 3px;
+ padding: 2px 8px;
+ margin: 2px 2px;
+ float: right;
+}
+
+.codemirror_buttons li.locales-group-item {
+ background: #ddd;
+}
+
+.codemirror_buttons li.selected-locales-group-item {
+ background: #3D576D;
+ color: white;
+}
+
+ul.codemirror_buttons li.selected-locales-group-item a.remove-locale {
+ color: #ddd;
+ font-size: 12px;
+ text-decoration: none;
+ display: inline-block;;
+ margin-left: 4px;
+}
+
+ul.codemirror_buttons li.selected-locales-group-item a.remove-locale:hover {
+ color: #f44;
+}
+
+ul.codemirror_buttons li.locales-group-item a.remove-locale {
+ color: #333;
+ font-size: 12px;
+ text-decoration: none;
+ display: inline-block;;
+ margin-left: 4px;
+}
+
+ul.codemirror_buttons li.locales-group-item a.remove-locale:hover {
+ color: #c00;
+}
+
+.codemirror_buttons li.unavailable-locales-group-item {
+ background: white;
+ color: gray;
+ border: 1px solid #ccc;
+ margin: 1px 2px;
+}
+
+.codemirror_buttons li:hover.selected-locales-group-item {
+ color: #fff;
+}
+
.codemirror_buttons li:hover {
color: #ff6600;
}
6 app/components/page_parts/_page_part.html.erb
View
@@ -0,0 +1,6 @@
+<%= form.fields_for field.name, page_part, :child_index => child_index do |page_part_builder| %>
+ <% field.children.each do |field| %>
+ <%= field.render :form, parent_controller, page_part_builder.object, :builder => page_part_builder %>
+ <% end %>
+ <%= page_part_builder.hidden_field :id, :data => { :acts => 'id' } if page_part_builder.object.persisted? %>
+<% end %>
18 app/components/page_parts/_page_part_locales.html.erb
View
@@ -0,0 +1,18 @@
+<ul class="rui-tabs localized-tabs" data-tabs="{disablable: true, onSelect: page_part_locale_select, onEnable: page_part_locale_enable, onDisable: page_part_locale_disable}" data-new-panel="<%= render('page_part', :form => form, :page_part => PagePart.new, :child_index => 'new_tab_panel_locale_index').gsub(/\n/, '').strip %>" data-new-panel-variable="new_tab_panel_locale_index">
+ <ul class="rui-tabs-list">
+ <% I18n.available_locales.each do |locale| %>
+ <li class="rui-tabs-tab<%= ' rui-tabs-disabled' unless page_parts[locale] || locale == I18n.default_locale %>" data-locale="<%= locale %>">
+ <%= link_to "#page_part_tab_#{index}_#{locale}" do %>
+ <%= locale.to_s.humanize %>
+ <% end %>
+ </li>
+ <% end %>
+ </ul>
+ <% I18n.available_locales.each do |locale| %>
+ <% if page_parts[locale] %>
+ <li id="<%= "page_part_tab_#{index}_#{locale}" %>" class="rui-tabs-panel">
+ <%= render 'page_part', :form => form, :page_part => page_parts[locale], :child_index => child_index %>
+ </li>
+ <% end %>
+ <% end %>
+</ul>
36 app/components/page_parts/form.html.erb
View
@@ -1,8 +1,9 @@
-<%= fields_for @record do |f| %>
- <ul id="<%= field.name %>" class="rui-tabs" data-tabs="{closable: true, scrollTabs: true, Cookie: {}, onSelect: page_part_tab_select, onRemove: page_part_tab_remove, addButton: page_part_tab_add}">
+<%= component_fields_for @record do |f| %>
+ <ul id="<%= field.name %>" class="rui-tabs" data-tabs="{closable: true, scrollTabs: true, Cookie: {}, onSelect: page_part_tab_select, onRemove: page_part_tab_remove, addButton: page_part_tab_add}" data-new-panel="<%= (localized? ? render('page_part_locales', :form => f, :page_parts => {}, :index => 'new_tab_panel_index') : render('page_part', :form => f, :page_part => PagePart.new, :child_index => 'new_tab_panel_index')).gsub(/\n/, '').strip %>" data-new-panel-variable="new_tab_panel_index">
<ul class="rui-tabs-list">
- <% @record.send(field.name).each_with_index do |page_part, index| %>
- <li>
+ <% @record.send(localized? ? "#{field.name}_translations" : field.name).each_with_index do |page_part, index| %>
+ <% page_part = page_part.values.first if localized? %>
+ <li class="rui-tabs-tab">
<%= link_to "#page_part_tab_#{index}" do %>
<%= page_part.name %>
<% if page_part.errors[:name].present? %>
@@ -14,29 +15,14 @@
</li>
<% end %>
</ul>
- <% @record.send(field.name).each_with_index do |page_part, index| -%>
- <li id="<%= "page_part_tab_#{index}" %>" class="rui-tabs-panel">
- <%= f.fields_for field.name, page_part do |page_part_builder| %>
- <% field.children.each do |field| %>
- <%= field.render :form, parent_controller, page_part_builder.object, :builder => page_part_builder %>
- <% end %>
- <%= page_part_builder.hidden_field :id unless page_part_builder.object.persisted? %>
+ <% @record.send(localized? ? "#{field.name}_translations" : field.name).each_with_index do |page_part, index| -%>
+ <li id="<%= "page_part_tab_#{index}" %>" class="rui-tabs-panel" data-name="<%= localized? ? page_part.values.first.name : page_part.name %>">
+ <% if localized? %>
+ <%= render 'page_part_locales', :form => f, :page_parts => page_part, :index => index, :child_index => nil %>
+ <% else %>
+ <%= render 'page_part', :form => f, :page_part => page_part, :child_index => nil %>
<% end %>
</li>
<% end -%>
</ul>
- <div id="page_parts_marked_for_destroy">
- </div>
-
- <% new_page_part_tab_panel = capture do %>
- <%= f.fields_for field.name, PagePart.new, :child_index => 'new_page_part_tab_panel_index' do |page_part_builder| %>
- <% field.children.each do |field| %>
- <%= field.render :form, parent_controller, page_part_builder.object, :builder => page_part_builder %>
- <% end %>
- <% end %>
- <% end %>
-
- <%= javascript_tag do %>
- var new_page_part_tab_panel = '<%= j new_page_part_tab_panel.strip.html_safe %>'
- <% end %>
<% end %>
8 app/components/page_parts_component.rb
View
@@ -1,7 +1,15 @@
class PagePartsComponent < Puffer::Component::Base
+ helper_method :localized?
+
def form
render
end
+private
+
+ def localized?
+ !!field.options[:localized]
+ end
+
end
5 db/migrate/20120817143224_add_locale_to_page_parts.rb
View
@@ -0,0 +1,5 @@
+class AddLocaleToPageParts < ActiveRecord::Migration
+ def change
+ add_column :page_parts, :locale, :string
+ end
+end
7 lib/puffer_pages.rb
View
@@ -28,6 +28,13 @@ class LayoutMissed < PufferPagesError
mattr_accessor :codemirror_buttons
self.codemirror_buttons = [:fullscreen]
+ mattr_accessor :localize
+ self.localize = false
+
+ def self.localize?
+ localize == true
+ end
+
def self.setup
yield self
end
7 lib/puffer_pages/backends/controllers/pages_base.rb
View
@@ -31,10 +31,11 @@ class PufferPages::PagesBase < Puffer::TreeBase
form do
field :name
field :slug
- field :page_parts, :type => :page_parts do
+ field :page_parts, :type => :page_parts, :localized => PufferPages.localize? do
field :body, :type => :codemirror, :input_only => true
- field :name, :type => :hidden
- field :_destroy, :type => :hidden, :html => { :class => 'destroy_mark' }
+ field :locale, :type => :hidden, :html => { :data => { :acts => 'locale' } }
+ field :name, :type => :hidden, :html => { :data => { :acts => 'name' } }
+ field :_destroy, :type => :hidden, :html => { :data => { :acts => 'destroy' } }
end
field :layout_name, :select => :possible_layouts, :include_blank => false
field :status, :select => :possible_statuses, :include_blank => false
53 lib/puffer_pages/backends/models/page.rb
View
@@ -66,7 +66,18 @@ def self.to_drop *args
:dependent => :destroy,
:class_name => '::PagePart',
:validate => true,
- :inverse_of => :page
+ :inverse_of => :page,
+ :conditions => Proc.new { PufferPages.localize? ? {} : { :locale => I18n.default_locale } }
+
+ def page_parts_translations
+ @page_parts_translations ||= page_parts.group_by(&:name).map do |name, page_parts|
+ page_parts.inject({}) do |result, page_part|
+ result[page_part.locale] = page_part
+ result
+ end.with_indifferent_access
+ end
+ end
+
accepts_nested_attributes_for :page_parts, :allow_destroy => true
belongs_to :layout, :primary_key => :name, :foreign_key => :layout_name, :class_name => '::Layout'
@@ -99,7 +110,9 @@ def update_locations
after_initialize :build_main_part, :if => :root?
before_save :build_main_part, :if => :root?
def build_main_part
- page_parts.build(:name => PufferPages.primary_page_part_name) unless page_parts.map(&:name).include?(PufferPages.primary_page_part_name)
+ unless page_parts.map(&:name).include?(PufferPages.primary_page_part_name)
+ page_parts.build(:name => PufferPages.primary_page_part_name, :locale => I18n.default_locale)
+ end
end
statuses.each do |status_name|
@@ -118,10 +131,10 @@ def render context = {}
if inherited_layout
render_layout(inherited_layout.body, context)
else
- inherited_page_parts.reverse.map{|part|
+ inherited_page_parts.reverse.map do |part|
result = part.render(context, self)
part.main? ? result : "<% content_for :'#{part.name}' do %>#{result}<% end %>"
- }.join
+ end.join
end
end
@@ -150,11 +163,39 @@ def inherited_page_parts
end
def all_inherited_page_parts
- @all_inherited_page_parts ||= ::PagePart.where(:page_parts => {:page_id => self_and_ancestors.map(&:id)}).joins(:page).order("page_parts.name = '#{PufferPages.primary_page_part_name}' desc, page_parts.name, pages.lft desc")
+ locales = PufferPages.localize? ?
+ (I18n.respond_to?(:fallbacks) ?
+ I18n.fallbacks[I18n.locale] :
+ [I18n.locale]) :
+ [I18n.default_locale]
+
+ @all_inherited_page_parts ||= begin
+ parts = ::PagePart
+ .where(:page_parts => { :page_id => self_and_ancestors.map(&:id), :locale => locales })
+ .joins(:page)
+ .order("page_parts.name = '#{PufferPages.primary_page_part_name}' desc, page_parts.name, pages.lft desc")
+
+ dictionary = parts.inject({}) do |hash, part|
+ entry = hash[part.name] || {}
+
+ if entry[part.page_id].nil?
+ entry[part.page_id] = part
+ else
+ entry[part.page_id] = part if part.locale == I18n.locale.to_s
+ end
+
+ hash[part.name] = entry
+ hash
+ end
+
+ dictionary.values.inject([]) { |ary, parts| ary << parts.values }.flatten
+ end
end
def super_inherited_page_parts
- @super_inherited_page_parts ||= ::PagePart.where(:page_parts => {:page_id => ancestors.map(&:id)}).joins(:page).order("page_parts.name = '#{PufferPages.primary_page_part_name}' desc, page_parts.name, pages.lft desc")
+ @super_inherited_page_parts ||= ::PagePart
+ .where(:page_parts => { :page_id => ancestors.map(&:id) }).joins(:page)
+ .order("page_parts.name = '#{PufferPages.primary_page_part_name}' desc, page_parts.name, pages.lft desc")
end
def part name
13 lib/puffer_pages/backends/models/page_part.rb
View
@@ -4,8 +4,17 @@ class PufferPages::PagePart < ActiveRecord::Base
belongs_to :page, :class_name => '::Page', :inverse_of => :page_parts
- validates_presence_of :name
- validates_uniqueness_of :name, :scope => :page_id
+ validates_presence_of :name, :locale
+ validates_uniqueness_of :name, :scope => [:page_id, :locale]
+ validates_inclusion_of :locale, :in => I18n.available_locales.map(&:to_s)
+
+ after_initialize do |page_part|
+ page_part.locale = I18n.default_locale if page_part.locale.blank?
+ end
+
+ def locale=(value)
+ write_attribute :locale, value.present? ? value.to_s : nil
+ end
def render context = {}, page = page
render_liquid(body, page, context)
51 lib/puffer_pages/liquid/tags/translate.rb
View
@@ -0,0 +1,51 @@
+module PufferPages
+ module Liquid
+ module Tags
+
+ class Translate < ::Liquid::Tag
+ Syntax = /(#{QuotedFragment})\s+(#{QuotedFragment}+))?/
+
+ def initialize(tag_name, markup, tokens)
+ if markup =~ Syntax
+ @key = $1
+ @attributes = {}
+
+ markup.scan(TagAttributes) do |key, value|
+ @attributes[key] = value
+ end
+ else
+ raise SyntaxError.new("Error in tag 'include' - Valid syntax: translate key [option:value, option:value...]")
+ end
+
+ super
+ end
+
+ def parse(tokens)
+ end
+
+ def render(context)
+ key = context[@key]
+ attributes = {}
+ @attributes.each do |key, value|
+ attributes[key] = context[value]
+ end
+
+ if variable.is_a?(Array)
+ variable.collect do |variable|
+ context[@template_name[1..-2]] = variable
+ partial.render(context)
+ end
+ else
+ context[@template_name[1..-2]] = variable
+ partial.render(context)
+ end
+ end
+
+ end
+
+ end
+ end
+end
+
+Liquid::Template.register_tag('translate', PufferPages::Liquid::Tags::Translate)
+Liquid::Template.register_tag('t', PufferPages::Liquid::Tags::Translate)
10 puffer_pages.gemspec
View
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
s.add_development_dependency(%q<pg>, [">= 0"])
s.add_development_dependency(%q<mysql>, [">= 0"])
s.add_development_dependency(%q<rspec-rails>, [">= 0"])
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
s.add_development_dependency(%q<capybara>, [">= 0.4.0"])
s.add_development_dependency(%q<database_cleaner>, [">= 0"])
s.add_development_dependency(%q<forgery>, [">= 0"])
@@ -36,6 +37,11 @@ Gem::Specification.new do |s|
s.add_development_dependency(%q<guard>, [">= 0"])
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
- s.add_development_dependency(%q<libnotify>, [">= 0"])
- s.add_development_dependency(%q<rb-inotify>, [">= 0"])
+
+ if RUBY_PLATFORM =~ /darwin/i
+ s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
+ else
+ s.add_development_dependency(%q<libnotify>, [">= 0"])
+ s.add_development_dependency(%q<rb-inotify>, [">= 0"])
+ end
end
6 spec/dummy/app/controllers/application_controller.rb
View
@@ -1,6 +1,12 @@
class ApplicationController < ActionController::Base
protect_from_forgery
+ before_filter :setup_locale
+
+ def setup_locale
+ I18n.locale = params[:locale].presence || I18n.default_locale
+ end
+
def has_puffer_access? namespace
true
end
4 spec/dummy/config/application.rb
View
@@ -28,7 +28,9 @@ class Application < Rails::Application
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
- # config.i18n.default_locale = :de
+ config.i18n.default_locale = :en
+ config.i18n.available_locales = [:ru, :en, :cn]
+ config.i18n.fallbacks = true
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
2  spec/dummy/config/environments/development.rb
View
@@ -33,5 +33,5 @@
config.assets.compress = false
# Expands the lines which load the assets
- config.assets.debug = true
+ config.assets.debug = false
end
1  spec/dummy/config/initializers/puffer_pages.rb
View
@@ -0,0 +1 @@
+PufferPages.localize = true
5 spec/dummy/db/migrate/20120817143224_add_locale_to_page_parts.rb
View
@@ -0,0 +1,5 @@
+class AddLocaleToPageParts < ActiveRecord::Migration
+ def change
+ add_column :page_parts, :locale, :string
+ end
+end
3  spec/dummy/db/schema.rb
View
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20111117081813) do
+ActiveRecord::Schema.define(:version => 20120817143224) do
create_table "articles", :force => true do |t|
t.string "title"
@@ -36,6 +36,7 @@
t.integer "page_id"
t.datetime "created_at"
t.datetime "updated_at"
+ t.string "locale"
end
add_index "page_parts", ["name"], :name => "index_page_parts_on_name"
2  spec/integration/navigation_spec.rb
View
@@ -1,7 +1,7 @@
require 'spec_helper'
describe "Navigation" do
- include Capybara
+ include Capybara::DSL
it "should be a valid app" do
::Rails.application.should be_a(Dummy::Application)
40 spec/models/page_part_spec.rb
View
@@ -0,0 +1,40 @@
+# encoding: UTF-8
+require 'spec_helper'
+
+describe PagePart do
+ it { should be_a(PufferPages::Renderable) }
+
+ describe "validations" do
+ it { should validate_presence_of(:name) }
+ it { should validate_presence_of(:locale) }
+
+ describe do
+ before { Fabricate :page_part }
+ it { should validate_uniqueness_of(:name).scoped_to(:page_id, :locale) }
+ end
+ end
+
+ describe "default values" do
+ before { I18n.stub(:default_locale).and_return(:cn) }
+ specify { Fabricate(:page_part).locale.should == 'cn' }
+ end
+
+ describe "locale" do
+ subject(:page_part) { Fabricate.build :page_part }
+
+ context 'assigned a symbol' do
+ before { page_part.locale = :ru }
+ its(:locale) { should == 'ru' }
+ end
+
+ context 'assigned a string' do
+ before { page_part.locale = 'ru' }
+ its(:locale) { should == 'ru' }
+ end
+
+ context 'assigned nil' do
+ before { page_part.locale = nil }
+ its(:locale) { should be_nil }
+ end
+ end
+end
143 spec/models/page_spec.rb
View
@@ -14,9 +14,7 @@
describe 'attributes' do
- before :each do
- @root = Fabricate :page, :layout_name => 'foo_layout'
- end
+ before { @root = Fabricate :page, :layout_name => 'foo_layout' }
it 'should have nil slug location if root' do
@root.slug.should == nil
@@ -66,8 +64,15 @@
before :each do
@root = Fabricate :page, :layout_name => 'foo_layout'
@foo = Fabricate :page, :slug => 'foo', :parent => @root
- @bar = Fabricate :page, :slug => 'bar', :parent => @foo, :page_parts => [Fabricate(:page_part, :name => PufferPages.primary_page_part_name, :body => '4')]
- @baz = Fabricate :page, :slug => 'baz', :parent => @bar, :page_parts => [Fabricate(:page_part, :name => 'sidebar', :body => '5'), Fabricate(:page_part, :name => 'additional', :body => '3')]
+
+ @bar = Fabricate :page, :slug => 'bar', :parent => @foo,
+ :page_parts => [Fabricate(:page_part, :name => PufferPages.primary_page_part_name, :body => '4')]
+
+ @baz = Fabricate :page, :slug => 'baz',
+ :parent => @bar, :page_parts => [
+ Fabricate(:page_part, :name => 'sidebar', :body => '5'),
+ Fabricate(:page_part, :name => 'additional', :body => '3')
+ ]
@foo.page_parts = [Fabricate(:page_part, :name => 'sidebar', :body => '2')]
end
@@ -127,29 +132,125 @@
end
describe 'rendering' do
+ let!(:main_part_name) { PufferPages.primary_page_part_name }
+
+ context 'when localization is off' do
+ before { PufferPages.stub(:localize).and_return(false) }
+
+ let!(:main_part) { Fabricate :page_part, :name => main_part_name, :body => '{{ self.title }}' }
+ let!(:main_part_ru) { Fabricate :page_part, :name => main_part_name, :body => 'Ru-body', :locale => 'ru' }
+ let!(:sidebar_part) { Fabricate :page_part, :name => 'sidebar', :body => '{{ self.name }}' }
+ let!(:sidebar_part_ru) { Fabricate :page_part, :name => 'sidebar', :body => 'Ru-sidebar', :locale => 'ru' }
+ let!(:page) { Fabricate :page, :layout_name => 'foo_layout',
+ :page_parts => [main_part, main_part_ru, sidebar_part, sidebar_part_ru] }
+
+ context "default locale is English" do
+ before { I18n.stub(:default_locale).and_return(:en) }
+
+ it 'should render content_for blocks if rails layout used' do
+ result = page.render 'self' => PufferPages::Liquid::PageDrop.new(page)
+ result.should == "<% content_for :'sidebar' do %>#{page.name}<% end %>#{page.title}"
+ end
+
+ it 'should render layout' do
+ @layout = Fabricate :layout, :name => 'foo_layout', :body => "{% include 'body' %} {% include 'sidebar' %}"
+ result = page.render 'self' => PufferPages::Liquid::PageDrop.new(page)
+ result.should == "#{page.title} #{page.name}"
+ end
+
+ it 'should receive proper content type' do
+ page.content_type.should == 'text/html'
+ child_page = Fabricate :page, :slug => 'style.css', :parent => page
+ child_page.content_type.should == 'text/css'
+ end
+ end
- before :each do
- @root = Fabricate :page, :layout_name => 'foo_layout'
- @main = Fabricate :page_part, :name => PufferPages.primary_page_part_name, :body => '{{ self.title }}'
- @sidebar = Fabricate :page_part, :name => 'sidebar', :body => '{{ self.name }}'
- @root.page_parts = [@main, @sidebar]
+ context "default locale is Russian" do
+ before { I18n.stub(:default_locale).and_return(:ru) }
+
+ it 'should render content_for blocks if rails layout used' do
+ result = page.render 'self' => PufferPages::Liquid::PageDrop.new(page)
+ result.should == "<% content_for :'sidebar' do %>Ru-sidebar<% end %>Ru-body"
+ end
+
+ it 'should render layout' do
+ @layout = Fabricate :layout, :name => 'foo_layout', :body => "{% include 'body' %} {% include 'sidebar' %}"
+ result = page.render 'self' => PufferPages::Liquid::PageDrop.new(page)
+ result.should == "Ru-body Ru-sidebar"
+ end
+
+ it 'should receive proper content type' do
+ page.content_type.should == 'text/html'
+ child_page = Fabricate :page, :slug => 'style.css', :parent => page
+ child_page.content_type.should == 'text/css'
+ end
+ end
end
- it 'should render content_for blocks if rails layout used' do
- result = @root.render 'self' => PufferPages::Liquid::PageDrop.new(@root)
- result.should == "<% content_for :'sidebar' do %>#{@root.name}<% end %>#{@root.title}"
+ context 'when localization is on' do
+ before { I18n.stub(:default_locale).and_return(:en) }
+ before { PufferPages.stub(:localize).and_return(true) }
+
+ let!(:main_part_en) { Fabricate :page_part, :name => main_part_name, :body => 'En-body', :locale => 'en' }
+ let!(:main_part_ru) { Fabricate :page_part, :name => main_part_name, :body => 'Ru-body', :locale => 'ru' }
+ let!(:sidebar_part) { Fabricate :page_part, :name => 'sidebar', :body => 'En-sidebar' }
+ let!(:page) { Fabricate :page, :layout_name => 'foo_layout',
+ :page_parts => [main_part_en, main_part_ru, sidebar_part] }
+
+ describe '.page_parts_translations' do
+ specify { page.page_parts_translations.should == [{'en' => main_part_en, 'ru' => main_part_ru}, {'en' => sidebar_part}] }
+ end
+
+ context 'and current language is English' do
+ before { I18n.stub(:locale).and_return(:en) }
+
+ it 'should render content_for blocks if rails layout used' do
+ result = page.render 'self' => PufferPages::Liquid::PageDrop.new(page)
+ result.should == "<% content_for :'sidebar' do %>En-sidebar<% end %>En-body"
+ end
+
+ it 'should render layout' do
+ @layout = Fabricate :layout, :name => 'foo_layout', :body => "{% include 'body' %} {% include 'sidebar' %}"
+ result = page.render 'self' => PufferPages::Liquid::PageDrop.new(page)
+ result.should == "En-body En-sidebar"
+ end
+ end
+
+ context 'and current language is Russian' do
+ before { I18n.stub(:locale).and_return(:ru) }
+
+ it 'should render content_for blocks if rails layout used and fallback to the default locale for missing parts' do
+ result = page.render 'self' => PufferPages::Liquid::PageDrop.new(page)
+ result.should == "<% content_for :'sidebar' do %>En-sidebar<% end %>Ru-body"
+ end
+
+ it 'should render layout and fallback to the default locale for missing parts' do
+ @layout = Fabricate :layout, :name => 'foo_layout', :body => "{% include 'body' %} {% include 'sidebar' %}"
+ result = page.render 'self' => PufferPages::Liquid::PageDrop.new(page)
+ result.should == "Ru-body En-sidebar"
+ end
+ end
end
+ end
+
+ describe "page_parts" do
+
+ let!(:main_part) { Fabricate :page_part, :name => PufferPages.primary_page_part_name, :body => 'Lorem' }
+ let!(:main_part_ru) { Fabricate :page_part, :name => PufferPages.primary_page_part_name, :body => 'Ipsum', :locale => 'ru' }
+ let!(:page) { Fabricate :page, :layout_name => 'foo_layout', :page_parts => [main_part, main_part_ru] }
+
+ subject { page.page_parts(true) }
- it 'should render layout' do
- @layout = Fabricate :layout, :name => 'foo_layout', :body => "{% include 'body' %} {% include 'sidebar' %}"
- result = @root.render 'self' => PufferPages::Liquid::PageDrop.new(@root)
- result.should == "#{@root.title} #{@root.name}"
+ context 'when localization is on' do
+ before { PufferPages.stub(:localize?).and_return(true) }
+ it { should include(main_part) }
+ it { should include(main_part_ru) }
end
- it 'should receive proper content type' do
- @root.content_type.should == 'text/html'
- page = Fabricate :page, :slug => 'style.css', :parent => @root
- page.content_type.should == 'text/css'
+ context 'when localization is off' do
+ before { PufferPages.stub(:localize?).and_return(false) }
+ it { should include(main_part) }
+ it { should_not include(main_part_ru) }
end
end
2  spec/spec_helper.rb
View
@@ -35,7 +35,7 @@
config.mock_with :rspec
config.use_transactional_fixtures = false
-
+
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.strategy = :transaction
Please sign in to comment.
Something went wrong with that request. Please try again.