phrasing 2.1.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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