phrasing 2.1.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ class PhrasingPhraseVersionsController < ActionController::Base
2
+
3
+ def destroy
4
+ @phrasing_phrase_version = PhrasingPhraseVersion.find(params[:id])
5
+ @phrasing_phrase_version.destroy
6
+ redirect_to edit_phrasing_phrase_path(@phrasing_phrase_version.phrasing_phrase.id)
7
+ end
8
+
9
+ end
@@ -16,7 +16,7 @@ class PhrasingPhrasesController < ActionController::Base
16
16
  value_like = PhrasingPhrase.arel_table[:value].matches("%#{params[:search]}%")
17
17
  @phrasing_phrases = query.where(key_like.or(value_like)).order(:key)
18
18
  else
19
- @phrasing_phrases = query.order(:key)
19
+ @phrasing_phrases = query.where("value is not null").order(:key) + query.where("value is null").order(:key)
20
20
  end
21
21
 
22
22
  @locale_names = PhrasingPhrase.uniq.pluck(:locale)
@@ -53,11 +53,17 @@ class PhrasingPhrasesController < ActionController::Base
53
53
  end
54
54
 
55
55
  def upload
56
- PhrasingPhrase.import_yaml(params["file"].tempfile)
57
- redirect_to phrasing_phrases_path, notice: "YAML file uploaded successfully!"
56
+ number_of_changes = PhrasingPhrase.import_yaml(params["file"].tempfile)
57
+ redirect_to phrasing_phrases_path, notice: "YAML file uploaded successfully! Number of phrases changed: #{number_of_changes}."
58
58
  rescue Exception => e
59
59
  logger.info "\n#{e.class}\n#{e.message}"
60
- flash[:alert] = "There was an error processing your upload! ##{e.message}"
60
+ message = if params[:file].nil?
61
+ "Please choose a file."
62
+ else
63
+ "Please upload a valid YAML file."
64
+ end
65
+
66
+ flash[:alert] = "There was an error processing your upload! #{message}"
61
67
  render action: 'import_export', status: 400
62
68
  end
63
69
 
@@ -1,12 +1,17 @@
1
1
  module InlineHelper
2
+ # Normal phrase
3
+ # phrase("headline", url: www.infinum.co/yabadaba, inverse: true, interpolation: {min: 15, max: 20})
2
4
 
3
- def phrase(key, options = {}, *args)
4
- key = key.to_s
5
- if can_edit_phrases?
6
- @record = PhrasingPhrase.where(key: key).first || PhrasingPhrase.create_phrase(key)
7
- inline(@record, :value, options)
5
+ # Data model phrase
6
+ # phrase(@record, :title, inverse: true, class: phrase-record-title)
7
+
8
+ def phrase(*args)
9
+ if args[0].class == String or args[0].class == Symbol
10
+ key, options = args[0].to_s, args[1]
11
+ phrasing_phrase(key,options)
8
12
  else
9
- t(key, *args).html_safe
13
+ record, field_name, options = args[0], args[1], args[2]
14
+ inline(record, field_name, options || {})
10
15
  end
11
16
  end
12
17
 
@@ -16,18 +21,28 @@ module InlineHelper
16
21
  klass = 'phrasable'
17
22
  klass += ' phrasable_on' if edit_mode_on?
18
23
  klass += ' inverse' if options[:inverse]
24
+ klass += options[:class] if options[:class]
19
25
 
20
26
  url = phrasing_polymorphic_url(record, field_name)
21
27
 
22
28
  content_tag(:span, { class: klass, contenteditable: edit_mode_on?, spellcheck: false, "data-url" => url}) do
23
- (record.send(field_name) || record.try(:key) || "#{field_name}-#{record.id}").to_s.html_safe
29
+ (record.send(field_name) || record.try(:key)).to_s.html_safe
24
30
  end
25
-
26
31
  end
27
32
 
28
33
  alias_method :model_phrase, :inline
29
34
 
30
35
  private
36
+
37
+ def phrasing_phrase(key, options = {})
38
+ key = key.to_s
39
+ if can_edit_phrases?
40
+ @record = PhrasingPhrase.where(key: key).first || PhrasingPhrase.create_phrase(key)
41
+ inline(@record, :value, options || {})
42
+ else
43
+ options.try(:[], :interpolation) ? t(key, options[:interpolation]).html_safe : t(key).html_safe
44
+ end
45
+ end
31
46
 
32
47
  def edit_mode_on?
33
48
  if cookies["editing_mode"].nil?
@@ -38,7 +53,6 @@ module InlineHelper
38
53
  end
39
54
  end
40
55
 
41
-
42
56
  def phrasing_polymorphic_url(record, attribute)
43
57
  resource = Phrasing.route
44
58
  "#{root_url}#{resource}/remote_update_phrase?klass=#{record.class.to_s}&id=#{record.id}&attribute=#{attribute}"
@@ -1,20 +1,18 @@
1
1
  class PhrasingPhrase < ActiveRecord::Base
2
2
 
3
- unless ENV['PHRASING_DEBUG']
4
- self.logger = Logger.new('/dev/null')
5
- end
6
-
7
3
  validates_presence_of :key, :locale
8
4
 
9
- # These validation methods are used so the YAML file can be exported/imported properly.
10
- validate :check_ambiguity, on: :create, :unless => Proc.new { |phrase| phrase.key.nil? }
11
- validate :key_muts_not_end_with_a_dot, on: :create, :unless => Proc.new { |phrase| phrase.key.nil? }
5
+ validate :uniqueness_of_key_on_locale_scope, on: :create
6
+
7
+ has_many :versions, dependent: :destroy, class_name: "PhrasingPhraseVersion"
8
+
9
+ after_update :version_it
12
10
 
13
11
  def self.create_phrase(key)
14
12
  phrasing_phrase = PhrasingPhrase.new
15
- phrasing_phrase.key = key.to_s
16
- phrasing_phrase.value = key.to_s.humanize
17
13
  phrasing_phrase.locale = I18n.locale
14
+ phrasing_phrase.key = key.to_s
15
+ phrasing_phrase.value = key.to_s
18
16
  phrasing_phrase.save!
19
17
  phrasing_phrase
20
18
  end
@@ -22,80 +20,43 @@ class PhrasingPhrase < ActiveRecord::Base
22
20
  module Serialize
23
21
 
24
22
  def import_yaml(yaml)
23
+ number_of_changes = 0
25
24
  hash = YAML.load(yaml)
26
25
  hash.each do |locale, data|
27
- hash_flatten(data).each do |key, value|
28
- c = where(key: key, locale: locale).first
29
- c ||= new(key: key, locale: locale)
30
- c.value = value
31
- c.save
32
- end
33
- end
34
- end
35
-
36
- # {"foo"=>{"a"=>"1", "b"=>"2"}} ----> {"foo.a"=>1, "foo.b"=>2}
37
- def hash_flatten(hash)
38
- result = {}
39
- hash.each do |key, value|
40
- if value.is_a? Hash
41
- hash_flatten(value).each { |k,v| result["#{key}.#{k}"] = v }
42
- else
43
- result[key] = value
26
+ data.each do |key, value|
27
+ phrase = where(key: key, locale: locale).first || new(key: key, locale: locale)
28
+ if phrase.value != value
29
+ phrase.value = value
30
+ number_of_changes += 1
31
+ phrase.save
32
+ end
44
33
  end
45
34
  end
46
- result
35
+ number_of_changes
47
36
  end
48
37
 
49
38
  def export_yaml
50
39
  hash = {}
51
- where("value is not null").each do |c|
52
- hash_fatten!(hash, [c.locale].concat(c.key.split(".")), c.value)
40
+ where("value is not null").each do |phrase|
41
+ hash[phrase.locale] ||= {}
42
+ hash[phrase.locale][phrase.key] = phrase.value
53
43
  end
54
44
  hash.to_yaml
55
45
  end
56
46
 
57
- # ({"a"=>{"b"=>{"e"=>"f"}}}, ["a","b","c"], "d") ----> {"a"=>{"b"=>{"c"=>"d", "e"=>"f"}}}
58
- def hash_fatten!(hash, keys, value)
59
- if keys.length == 1
60
- hash[keys.first] = value
61
- else
62
- head = keys.first
63
- rest = keys[1..-1]
64
- hash[head] ||= {}
65
- hash_fatten!(hash[head], rest, value)
66
- end
67
- end
68
-
69
47
  end
70
48
 
71
49
  extend Serialize
72
50
 
73
51
  private
74
52
 
75
- def check_ambiguity
76
- check_ambiguity_on_ancestors
77
- check_ambiguity_on_successors
78
- end
79
-
80
- def check_ambiguity_on_ancestors
81
- stripped_key = key
82
- while stripped_key.include?('.')
83
- stripped_key = stripped_key.split('.')[0..-2].join('.')
84
- if PhrasingPhrase.where(key: stripped_key).count > 0
85
- errors.add(:key, "can't be named '#{key}', there already exists a key named '#{stripped_key}'. Ambiguous calling!")
86
- end
87
- end
53
+ def uniqueness_of_key_on_locale_scope
54
+ errors.add(:key, "Duplicate entry #{key} for locale #{locale}") unless PhrasingPhrase.where(key: key).where(locale: locale).empty?
88
55
  end
89
56
 
90
- def check_ambiguity_on_successors
91
- key_successor = "#{key}."
92
- if PhrasingPhrase.where(PhrasingPhrase.arel_table[:key].matches("#{key_successor}%")).count > 0
93
- errors.add(:key, "can't be named '#{key}', there already exists one or multiple keys beginning with '#{key_successor}'. Ambiguous calling!")
57
+ def version_it
58
+ if value_was != value
59
+ PhrasingPhraseVersion.create(phrasing_phrase_id: id,value: value)
94
60
  end
95
61
  end
96
-
97
- def key_muts_not_end_with_a_dot
98
- errors.add(:key, "mustn't end with a dot") if key[-1] == "."
99
- end
100
-
101
62
  end
@@ -0,0 +1,3 @@
1
+ class PhrasingPhraseVersion < ActiveRecord::Base
2
+ belongs_to :phrasing_phrase
3
+ end
@@ -3,6 +3,7 @@
3
3
  %head
4
4
  %title Phrasing
5
5
  = stylesheet_link_tag "phrasing_engine", :media => "all"
6
+ = javascript_include_tag "phrasing_engine"
6
7
  %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/
7
8
  %body
8
9
  #page
@@ -1,8 +1,8 @@
1
1
  #header
2
2
  %h1= link_to "Phrasing", phrasing_phrases_path
3
3
  %ul
4
- - if root_path
5
- %li= link_to "Home page", root_path
6
4
  %li= link_to "Phrases", phrasing_phrases_path
7
5
  %li= link_to "Import / Export", import_export_phrasing_phrases_path
8
- %li= link_to "Help", help_phrasing_phrases_path
6
+ %li= link_to "Help", help_phrasing_phrases_path
7
+ - if root_path
8
+ %li= link_to "Home page", root_path
@@ -1,7 +1,23 @@
1
1
  .edit
2
2
  %h2= @phrasing_phrase.key
3
- = button_to "Delete this item", phrasing_phrase_path(@phrasing_phrase), :method => :delete, :onclick => "return confirm('Are you sure?');"
3
+ = link_to "Delete Phrase", phrasing_phrase_path(@phrasing_phrase), class: "btn btn-danger delete-phrase", method: :delete, onclick: "return confirm('Are you sure?');"
4
4
  = form_for @phrasing_phrase, :url => { :action => "update" } do |f|
5
5
  = f.text_area :value, :rows => 12
6
- = f.submit "Update"
7
- = link_to "Cancel", phrasing_phrases_path
6
+ = f.submit "Update", class: "btn btn-success submit-edit-phrase"
7
+ %br
8
+ - unless @phrasing_phrase.versions.empty?
9
+ %br
10
+ %h2 Previous Versions
11
+ %br
12
+ %table.phrase-versions
13
+ %tr
14
+ %th Value
15
+ %th Created_at
16
+ %th
17
+ %th
18
+ - @phrasing_phrase.versions.reverse.each do |version|
19
+ %tr
20
+ %td.phrasing-version-value= version.value.html_safe
21
+ %td.phrasing-version-created_at= version.created_at.strftime("%d-%m-%Y %H:%M:%S")
22
+ %td= link_to "Revert", phrasing_phrase_path(@phrasing_phrase.id, phrasing_phrase: {value: version.value}), class: "btn btn-success", method: :put
23
+ %td= link_to "Delete", phrasing_phrase_version_path(version.id), class: "btn btn-danger", method: :delete, onclick: "return confirm('Are you sure?');"
@@ -3,15 +3,18 @@
3
3
  - locale_options = options_for_select([nil] + @locale_names.map{|l| [l,l]}, params[:locale])
4
4
  = select_tag 'locale', locale_options
5
5
  = text_field_tag :search, params[:search], :placeholder => 'Search for keys or values', :size => 40
6
- = submit_tag 'Search'
6
+ = submit_tag 'Search', class: "btn btn-success"
7
7
  - if @phrasing_phrases.any?
8
- %table
9
- %tr
10
- %th Key
11
- %th Value
12
- - @phrasing_phrases.each do |t|
8
+ %table.all-phrases
9
+ %thead
13
10
  %tr
14
- %td.key
15
- = link_to "#{t.key}", edit_phrasing_phrase_path(t)
16
- %td.value
17
- = t.value.try(:html_safe)
11
+ %th Key
12
+ %th Value
13
+ %tbody
14
+ - @phrasing_phrases.each do |t|
15
+ %tr{onclick: "document.location = '/#{Phrasing.route}/#{t.id}/edit'"}
16
+ %td.key
17
+ = link_to edit_phrasing_phrase_path(t) do
18
+ = t.key
19
+ %td.value
20
+ = t.value.try(:html_safe)
@@ -9,4 +9,5 @@ Rails.application.routes.draw do
9
9
  put 'remote_update_phrase'
10
10
  end
11
11
  end
12
+ resources :phrasing_phrase_versions, :as => 'phrasing_phrase_versions', :controller => 'phrasing_phrase_versions', only: [:destroy]
12
13
  end
@@ -6,6 +6,5 @@ class CreatePhrasingPhrases < ActiveRecord::Migration
6
6
  t.text :value
7
7
  t.timestamps
8
8
  end
9
- add_index :phrasing_phrases, [:locale, :key], :unique => true
10
9
  end
11
10
  end
@@ -0,0 +1,9 @@
1
+ class CreatePhrasingPhraseVersions < ActiveRecord::Migration
2
+ def change
3
+ create_table :phrasing_phrase_versions do |t|
4
+ t.string :phrasing_phrase_id
5
+ t.text :value
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -1,6 +1,8 @@
1
1
  require 'phrasing'
2
2
  require "phrasing/implementation"
3
3
  require "phrasing/simple"
4
+ require 'jquery-rails'
5
+ require 'jquery-cookie-rails'
4
6
 
5
7
  module Phrasing
6
8
  module Rails
@@ -8,7 +10,7 @@ module Phrasing
8
10
  initializer :assets, :group => :all do
9
11
  ::Rails.application.config.assets.paths << ::Rails.root.join('app', 'assets', 'fonts')
10
12
  ::Rails.application.config.assets.paths << ::Rails.root.join('app', 'assets', 'images')
11
- ::Rails.application.config.assets.precompile += ['editor.js', 'phrasing_engine.css', 'icomoon.dev.svg', 'icomoon.svg', 'icomoon.eot', 'icomoon.ttf', 'icomoon.woff', 'phrasing_information_icon.png']
13
+ ::Rails.application.config.assets.precompile += ['editor.js', 'phrasing_engine.css', 'phrasing_engine.js', 'icomoon.dev.svg', 'icomoon.svg', 'icomoon.eot', 'icomoon.ttf', 'icomoon.woff', 'phrasing_information_icon.png']
12
14
  end
13
15
  end
14
16
  end
@@ -11,7 +11,11 @@ module Phrasing
11
11
 
12
12
  value = super(locale, key, scope, options)
13
13
  if value.is_a?(String) || value.nil?
14
- PhrasingPhrase.create(locale: locale.to_s, key: scoped_key, value: value)
14
+ phrasing_phrase = PhrasingPhrase.new
15
+ phrasing_phrase.locale = locale.to_s
16
+ phrasing_phrase.key = scoped_key
17
+ phrasing_phrase.value = value
18
+ phrasing_phrase.save
15
19
  end
16
20
  value
17
21
  end
@@ -1,3 +1,3 @@
1
1
  module Phrasing
2
- VERSION = "2.1.3"
2
+ VERSION = "3.0.0"
3
3
  end
@@ -3,14 +3,17 @@ namespace :phrasing do
3
3
  task :install do
4
4
  Rake::Task["phrasing_rails_engine:install:migrations"].invoke
5
5
  Rake::Task["phrasing:install_initializer"].invoke
6
- Rake::Task["phrasing:phrasable_creator"].invoke
6
+ Rake::Task["phrasing:install_phrasing_helper"].invoke
7
7
  end
8
8
 
9
9
  desc "Create the initializer file"
10
10
  task :install_initializer do
11
11
  filepath = Rails.root.join *%w(config initializers phrasing.rb)
12
- File.open(filepath, 'w') do |f|
13
- f << <<-CONFIG
12
+ if File.exists?(filepath)
13
+ alert "Phrasing config file already exists.\n"
14
+ else
15
+ File.open(filepath, 'w') do |f|
16
+ f << <<-CONFIG
14
17
  Phrasing.setup do |config|
15
18
  config.route = 'phrasing'
16
19
  end
@@ -20,17 +23,21 @@ end
20
23
  Phrasing.whitelist = []
21
24
  # Phrasing.allow_update_on_all_models_and_attributes = true;
22
25
  CONFIG
26
+ end
27
+ notice("created")
28
+ puts " config/intiializers/phrasing.rb"
23
29
  end
24
- greenify("You can change the default route and whitelist editable attributes in the phrasing initializer created in the config/intiializers folder.")
25
30
  end
26
31
 
27
32
 
28
33
  desc "Create the PhrasingHelper file"
29
- task :phrasable_creator do
34
+ task :install_phrasing_helper do
30
35
  filepath = Rails.root.join *%w(app helpers phrasing_helper.rb)
31
-
32
- File.open(filepath, 'w') do |f|
33
- f << <<-MODULE
36
+ if File.exists?(filepath)
37
+ alert "Phrasing helper file already exists.\n"
38
+ else
39
+ File.open(filepath, 'w') do |f|
40
+ f << <<-MODULE
34
41
  module PhrasingHelper
35
42
  # You must implement the can_edit_phrases? method.
36
43
  # Example:
@@ -44,14 +51,20 @@ module PhrasingHelper
44
51
  end
45
52
  end
46
53
  MODULE
47
- end
48
- greenify("A PhrasingHelper has been created in your app/helper folder. Please implement the can_edit_phrases? method.")
49
- greenify("Now run 'rake db:migrate'.")
54
+ end
55
+ notice("created")
56
+ puts " app/helpers/phrasing_helper.rb"
57
+ notice "Now run 'rake db:migrate'.\n"
58
+ end
50
59
  end
51
60
 
52
61
 
53
62
  end
54
63
 
55
- def greenify(text)
56
- puts "\033[#{32}m#{text}\033[0m"
64
+ def notice(text)
65
+ print "\033[#{32}m#{text}\033[0m"
66
+ end
67
+
68
+ def alert(text)
69
+ print "\033[#{31}m#{text}\033[0m"
57
70
  end